Error handling

try / catch / finally

try {
    throw "something went wrong";
} catch (String e) {
    Konsol:Print("Caught: " + e);
} finally {
    Konsol:Print("always runs");
}

throw

Use throw to raise an exception from your own code:

function validateAge(Number age) {
    if (age < 0) { throw "age cannot be negative"; }
    if (age > 150) { throw "age out of realistic range"; }
}

try {
    validateAge(-5);
} catch (String e) {
    Konsol:Print("Validation failed: " + e);
}

Typed exceptions

The engine raises typed exceptions for certain runtime errors:

Error output format

KonsolScript Error (line 5): undefined variable 'total'
  5 | Konsol:Print(total);
    |              ^^^^^

Uncaught throw exceptions show the same context plus a full stack trace:

Uncaught exception (line 12): something went wrong
  12 | throw "something went wrong";

Stack trace:
  at inner (called from line 8)
  at outer (called from line 3)
  at main

Calling a method on a class that was never registered raises a clear error:

Runtime error at line 3: unknown class 'Sample' — missing #include?

Examples

Error handling

// 08_errors.ks — try / catch / finally / throw

Konsol:Print("=== Error Handling ===");

// Basic try/catch
Konsol:Print("--- basic catch ---");
try {
    Konsol:Print("before throw");
    throw "something went wrong";
    Konsol:Print("this should not print");
} catch (Exception e) {
    Konsol:Print("caught: ${e.code}");
}
Konsol:Print("execution continues");

// finally always runs
Konsol:Print("--- finally ---");
try {
    Konsol:Print("try block");
    throw "oops";
} catch (String err) {
    Konsol:Print("catch: ${err}");
} finally {
    Konsol:Print("finally: always runs");
}

// finally without exception
Konsol:Print("--- finally (no exception) ---");
try {
    Konsol:Print("no throw here");
} catch (String e) {
    Konsol:Print("never reached");
} finally {
    Konsol:Print("finally still runs");
}

// Catch without parameter
Konsol:Print("--- bare catch ---");
try {
    throw "ignored message";
} catch {
    Konsol:Print("caught without binding");
}

// Nested try/catch
Konsol:Print("--- nested ---");
try {
    Konsol:Print("outer try");
    try {
        Konsol:Print("inner try");
        throw "inner error";
    } catch (String inner) {
        Konsol:Print("inner catch: ${inner}");
        throw "re-thrown from inner";
    }
} catch (String outer) {
    Konsol:Print("outer catch: ${outer}");
}

// Throw a number (converted to string)
Konsol:Print("--- throw number ---");
try {
    throw 404;
} catch (String code) {
    Konsol:Print("error code: ${code}");
}

// Conditional throw
Konsol:Print("--- conditional throw ---");
function divide(Number a, Number b) : Number {
    if (b == 0) {
        throw "division by zero";
    }
    return a / b;
}

try {
    Var:Number r = divide(10, 2);
    Konsol:Print("10 / 2 = ${r}");
    Var:Number bad = divide(5, 0);
} catch (String e) {
    Konsol:Print("caught from function: ${e}");
}

Exceptions

// 19_exception.ks — Exception class: structured errors, subclassing

Konsol:Print("=== Exception Class ===");

// Exception is a built-in class (extends Object):
//   Fields:  message (String), type (String), code (Number)
//   Methods: init(String type, String message)
//            toString() → "[type] message"
//            getType()  → "Exception" (inherited from Object)
//            isInstanceOf(String t) → bool

// ── Basic Exception usage ─────────────────────────────────────────────────────
Konsol:Print("--- basic ---");

Class:Exception ex;
ex.init("RuntimeError", "something went wrong");

Var:String exStr;
exStr = ex.toString();
Konsol:Print("toString = ${exStr}");

Var:String exType;
exType = ex.getType();
Konsol:Print("getType  = ${exType}");

Var:Boolean isExc;
isExc = ex.isInstanceOf("Exception");
Konsol:Print("isInstanceOf Exception = ${isExc}");

Var:Boolean isObj;
isObj = ex.isInstanceOf("Object");
Konsol:Print("isInstanceOf Object    = ${isObj}");

// ── Throw and catch using Exception.message ───────────────────────────────────
Konsol:Print("--- throw + catch ---");

try {
    Class:Exception e;
    e.init("ValueError", "expected a positive number");
    throw e.message;
} catch (String msg) {
    Konsol:Print("caught: ${msg}");
}

// ── Using Exception in a guard function ───────────────────────────────────────
Konsol:Print("--- guard function ---");

function safeDivide(Number a, Number b) : Number {
    if (b == 0) {
        Class:Exception ex;
        ex.type    = "MathError";
        ex.message = "division by zero";
        ex.code    = 100;
        throw ex.message;
    }
    return a / b;
}

try {
    Var:Number r = safeDivide(10, 2);
    Konsol:Print("10 / 2 = ${r}");
    Var:Number bad = safeDivide(5, 0);
} catch (String err) {
    Konsol:Print("error: ${err}");
}

// ── Custom Exception subclass ─────────────────────────────────────────────────
Konsol:Print("--- subclassing Exception ---");

Class:Create(FileException extends Exception) {
    Var:String filename;

    function initFile(String fname, String msg) {
        filename = fname;
        type     = "FileException";
        message  = msg;
    }

    function toString() : String {
        return "[" + type + "] " + filename + ": " + message;
    }
}

Class:FileException fe;
fe.initFile("data.txt", "file not found");

Var:String feStr;
feStr = fe.toString();
Konsol:Print("FileException toString = ${feStr}");

Var:String feType;
feType = fe.getType();
Konsol:Print("FileException getType  = ${feType}");

Var:Boolean feIsFile;
feIsFile = fe.isInstanceOf("FileException");
Konsol:Print("isInstanceOf FileException = ${feIsFile}");

Var:Boolean feIsExc;
feIsExc = fe.isInstanceOf("Exception");
Konsol:Print("isInstanceOf Exception     = ${feIsExc}");

Var:Boolean feIsObj;
feIsObj = fe.isInstanceOf("Object");
Konsol:Print("isInstanceOf Object        = ${feIsObj}");

// Throw and catch a FileException
try {
    Class:FileException e;
    e.initFile("config.json", "permission denied");
    throw e.message;
} catch (String err) {
    Konsol:Print("caught file error: ${err}");
}

// ── Custom Exception hierarchy ────────────────────────────────────────────────
Konsol:Print("--- exception hierarchy ---");

Class:Create(NetworkException extends Exception) {
    Var:Number statusCode;

    function initNet(Number code, String msg) {
        type       = "NetworkException";
        statusCode = code;
        message    = msg;
    }

    function toString() : String {
        return "[" + type + " " + statusCode + "] " + message;
    }
}

Class:Create(TimeoutException extends NetworkException) {
    Var:Number timeoutMs;

    function initTimeout(Number ms) {
        type      = "TimeoutException";
        timeoutMs = ms;
        message   = "request timed out after " + ms + "ms";
        statusCode = 408;
    }
}

Class:NetworkException ne;
ne.initNet(404, "endpoint not found");

Var:String neStr;
neStr = ne.toString();
Konsol:Print("NetworkException toString = ${neStr}");

Var:Boolean neIsNet;
neIsNet = ne.isInstanceOf("NetworkException");
Konsol:Print("isInstanceOf NetworkException = ${neIsNet}");

Var:Boolean neIsExc;
neIsExc = ne.isInstanceOf("Exception");
Konsol:Print("isInstanceOf Exception        = ${neIsExc}");

Class:TimeoutException te;
te.initTimeout(5000);

Var:String teStr;
teStr = te.toString();
Konsol:Print("TimeoutException toString = ${teStr}");

Var:Boolean teIsTimeout;
teIsTimeout = te.isInstanceOf("TimeoutException");
Konsol:Print("isInstanceOf TimeoutException  = ${teIsTimeout}");

Var:Boolean teIsNet;
teIsNet = te.isInstanceOf("NetworkException");
Konsol:Print("isInstanceOf NetworkException  = ${teIsNet}");

Var:Boolean teIsExc;
teIsExc = te.isInstanceOf("Exception");
Konsol:Print("isInstanceOf Exception         = ${teIsExc}");

Var:Boolean teIsObj;
teIsObj = te.isInstanceOf("Object");
Konsol:Print("isInstanceOf Object            = ${teIsObj}");

Var:Boolean teIsFile;
teIsFile = te.isInstanceOf("FileException");
Konsol:Print("isInstanceOf FileException     = ${teIsFile}");

// Catch exceptions by message regardless of subtype
Konsol:Print("--- catch any exception ---");

try {
    Class:TimeoutException t;
    t.initTimeout(3000);
    throw t.message;
} catch (String err) {
    Konsol:Print("caught timeout: ${err}");
}