Esc
Start typing to search...

Error Handling

Keel provides comprehensive error messages with helpful suggestions to improve developer experience.

Fuzzy Matching ("Did you mean?")

When you reference an undefined symbol, Keel suggests similar names:

import IO exposing (print)
let userName = "Alice"
let userAge = 30
print usrName
-- Error: Variable 'usrName' not found. Did you mean 'userName' or 'userAge'?
Try it

Multiple suggestions when relevant:

import IO exposing (print)

let userName = "Alice"
let userAge = 30
let userEmail = "alice@example.com"

print usrNme

-- Error: Variable 'usrNme' not found. Did you mean 'userName', 'userAge', or 'userEmail'?
Try it

Suggestions work for:

  • Variables and bindings
  • Function names
  • Module names
  • Enum types and variants
  • Type aliases

Module Function Typos

Suggestions also work for module function names:

import List
List.fold [1, 2, 3] 0
-- Error: Function 'fold' is not declared in module 'List'. Did you mean 'foldl' or 'foldr'?
Try it

Parser Errors

Keel provides clear messages for syntax errors.

Indentation Errors

fn example : Int -> Int
fn example x =
let y = 1    -- Error: Function body must be indented by at least 4 spaces
    x + y
Try it

Block Alignment

if True then
    0
  else         -- Error: 'else' must align with 'if'
    1
Try it

Block Nesting

let x =
x + 1          -- Error: Block must be indented more than parent
               -- Hint: Indent the block to 4 spaces
Try it

Type Definition Errors

type Direction = North | south    -- Error: Enum variant must start with uppercase
Try it

Record Type Alias Syntax

Using type instead of type alias for record types:

type Person = { name: String, age: Int }
-- Error: Expected enum variant, found record syntax
-- Hint: Use 'type alias' to define a record type alias.
Try it

Enum Variant Parentheses

Forgetting parentheses in enum variant data:

type Result a e = Ok a | Err e
-- Result OkType ErrType: first parameter is success, second is error
-- Error: Enum variant 'Ok' appears to have data without parentheses
-- Hint: Use `Ok(a)` instead of `Ok a`. Variant data requires parentheses.
Try it

Delimiter Balancing

Keel checks for mismatched, unclosed, and unexpected delimiters before parsing, producing precise error messages:

let x = (1 + 2
-- Error: Unclosed '(' — expected ')'
Try it
let x = [1, 2)
-- Error: Mismatched delimiter — '(' expected ')' but found ')'
Try it
let x = 1 + 2]
-- Error: Unexpected ']' — no matching '['
Try it

Tuple Pattern Type Annotations

Annotating a tuple pattern as a whole instead of its elements:

let addPair = |(x, y): (Int, Int)| x + y
-- Error: Type annotations on tuple patterns must be on individual elements
-- Hint: Use `|(x: Int, y: Int)|` instead of `|(x, y): (Int, Int)|`.
Try it

Compiler Errors

Undeclared Symbols

let x = unknownVar    -- Error: Variable 'unknownVar' is not declared
Try it

Type Mismatches

fn add: Int -> Int -> Int
fn add x y =
    x + y

add "hello" 5  -- Error: Expected Int but got String
Try it

Generic Type Annotations Required

Functions that return a generic type (like Json.parse) require a type annotation on the let binding so the compiler knows the concrete type:

import Json

let data = Json.parse "{\"x\": 1}"
-- Error: Generic function result requires a type annotation for variable 'data'
-- Hint: Add a type annotation to specify the expected type
Try it

Fix by adding a type annotation:

import Json

let data: Result { x: Int } String = Json.parse "{\"x\": 1}"
data
Try it

Scope Violations

fn example : Int -> Int
fn example x =
    let inner = x + 1
    inner

inner  -- Error: Variable 'inner' is not in scope
Try it

Helpful Suggestions for Common Mistakes

Keel detects common syntax patterns from other languages and provides helpful suggestions.

JavaScript-Style Record Syntax

{ name: "Alice", age: 30 }
-- Error: JavaScript-style record syntax is not allowed
-- Hint: Use `=` instead of `:` for record field assignment
-- Example: `{ name = "Alice" }`
Try it

Correct syntax:

{ name = "Alice", age = 30 }
Try it

Boolean Literals from Other Languages

let x = true     -- Error: 'true' is not a Keel keyword
                 -- Hint: Use `True` for boolean true
Try it

Correct syntax:

let x = True

let y = False

x && y
Try it

Null/Nil/None from Other Languages

let x = null     -- Error: 'null' is not a Keel keyword
                 -- Hint: Use `Nothing` for absent values
Try it

Correct syntax:

let present = Just 42

let absent = Nothing

case present of
    Just n -> "Got a value"
    Nothing -> "Nothing"
Try it

Keywords from Other Languages

return 5         -- Hint: Keel is expression-based; the last expression is the return value
match x of       -- Hint: Use `case ... of` for pattern matching
function add     -- Hint: Use `fn` to define functions
var x = 5        -- Hint: Use `let` for variable bindings
Try it

Correct syntax examples:

fn double: Int -> Int
fn double x =
    x * 2
    -- Pattern matching uses case...of

let value = Just 5

case value of
    Just n -> n * 2
    Nothing -> 0
Try it

Pattern Matching Errors

Type Mismatch in Patterns

case 42 of
    "hello" -> 1  -- Error: Pattern type mismatch: expected Int, but pattern is String
    _ -> 0
Try it

Wrong Constructor Type

case Just 5 of
    Ok n -> n  -- Error: Pattern type mismatch: expected Maybe, but pattern is Result (Ok)
    _ -> 0
Try it

Guard Type Errors

let x = 2

case x of
    n if n + 1 -> "bad"    -- Error: Guard expression must be Bool, found Int
    _ -> "ok"
Try it

Correct guard syntax:

let x = 5

case x of
    n if n > 0 -> "positive"
    n if n < 0 -> "negative"
    _ -> "zero"
Try it

Branch Type Mismatch

let x = 2

case x of
    1 -> 42        -- Int
    2 -> "hello"   -- Error: Case branches have incompatible types: Int and String
    _ -> 0
Try it

Correct (all branches return same type):

let x = 2

case x of
    1 -> "one"
    2 -> "two"
    _ -> "other"
Try it

Type Errors

Function Argument Type Mismatch

When you pass the wrong type to a function, Keel shows the expected and actual types along with the full function signature:

import List

List.map 42 [1, 2, 3]
-- Error: Type mismatch: expected (a -> b), found Int
-- Hint: Function signature: (a -> b) -> [a] -> [b]
--       Expected argument type: (a -> b), but got: Int
Try it
import String

String.length 42
-- Error: Type mismatch: expected String, found Int
-- Hint: Function signature: String -> Int
--       Expected argument type: String, but got: Int
Try it

The function signature in the hint helps you understand what the function expects, especially for higher-order functions with type variables.

Runtime Errors

Collection Bounds

let items =
    [1, 2, 3]

items[10]  -- Error: Index 10 out of bounds for list of size 3
Try it

Unsafe access (use List.nth for safe access):

let items =
    [1, 2, 3]

items[0]  -- 1
Try it

Composable Error Handling

Keel provides the Result and Maybe modules for functional, composable error handling without nested pattern matching.

Result Module

Transform and chain operations that might fail:

import Result

-- Transform success values
let mapped = Ok 5 |> Result.map (|x| x * 2)

-- Chain operations that might fail
let chained = Ok 5 |> Result.andThen (|x| if x > 0 then Ok x else Err "negative")

-- Provide default values
let defaulted = Err "failed" |> Result.withDefault 0

-- Transform error values
Err "bad" |> Result.mapError (|e| "Error: " ++ e)
Try it

Maybe Module

Transform and chain optional values:

import Maybe

-- Transform present values
let mapped = Just 5 |> Maybe.map (|x| x * 2)

-- Chain operations that might return Nothing
let chained = Just 5 |> Maybe.andThen (|x| if x > 0 then Just x else Nothing)

-- Provide default values
Nothing |> Maybe.withDefault 0
Try it

Converting Between Types

import Result

-- Maybe to Result (with error message)
let a = Just 5 |> Result.fromMaybe "was nothing"

-- Result to Maybe (discards error)
let c: Maybe Int = Ok 5 |> Result.toMaybe
let d: Result Int String = Err "x"
d |> Result.toMaybe
Try it

Best Practices

  1. Read error messages carefully — they often contain the exact fix
  2. Check the hints — suggestions point to Keel-specific syntax
  3. Use the playground — experiment with syntax in the browser
  4. Handle all cases — the compiler warns about incomplete pattern matches
  5. Use Result/Maybe modules — prefer map and andThen over nested pattern matching

Next Steps

Explore the Standard Library to see available modules and functions.