Skip to content

Common Errors

Understanding and fixing common Qosm errors.


Type errors

Unbound identifier

Error: Unbound identifier 'foo'

Cause: You referenced a name that doesn't exist in scope.

Fixes:

  • Check for typos in the name
  • If it's a module function, use qualified name: Module.function
  • If it's a capability, make sure it's enabled in the Capabilities panel
  • If it's defined later in the file, move it above the usage (Qosm bindings must be defined before use)

Type mismatch

Error: Expected String but got Int

Cause: A value has a different type than expected.

Common causes:

  • Using + instead of ++ for string concatenation
  • Forgetting to_string when building strings: `Count: {{ to_string n }}`
  • Passing arguments in the wrong order (Qosm functions are curried)

Effect not declared

Error: Undeclared effect 'Http.Get'

Cause: Your code uses a capability whose effect isn't in scope.

Fix: Enable the relevant capability in the workspace Capabilities panel. The effect and extern declarations are generated automatically.

Missing semicolon

Error: Parse error at line N

Cause: Often a missing ; at the end of a top-level binding.

Fix: Every top-level let, type, effect, and extern must end with ;:

let x = 1;     // semicolon required
let y = x + 1; // even the last one

Runtime errors

QosmError variants

All capability calls return Result<T, QosmError>. The error constructors are:

| Constructor | When it occurs | |-------------|----------------| | ModelError{message: _} | LLM call failed (network, rate limit, invalid response) | | ParseError{message: _} | JSON parsing failed (invalid format or schema mismatch) | | PermissionError{message: _} | Capability access denied (domain restriction, missing credential) | | FunctionError{message: _} | General function execution error |

Access the message with .message e:

match result with (
| Err{value: e} -> "Error: " ++ .message e
| Ok{value: v} -> to_string v)

Match failure

Error: Match failure

Cause: A match expression didn't find a matching branch.

Fix: Add a wildcard branch or handle all cases:

match value with (
| Some{value: x} -> x
| None -> 0)          // handle the None case

Common mistakes

| Mistake | Fix | |---------|-----| | person.name | .name person (prefix field access) | | "hello" + " world" | "hello" ++ " world" (use ++ for strings) | | if x then a else b | match x with (\| true -> a \| false -> b) | | arr.map(f) | map f arr (curried, not method syntax) | | [x, ...rest] in expression | append [x] rest (spread is pattern-only) | | greet @{text: String} "hi" | my_model @{text: String} \...`(@Type goes on the extern) | |let x = 1inside match arm |let x = 1 in ...(usein` form inside expressions) |