Skip to content

Error Handling

Every lash error has two parts:

  • Problem: A plain-English description of what went wrong.
  • Suggestion: An actionable step to fix it.

This applies to all errors: command failures, type mismatches, method errors, and syntax problems.

lash supports three output formats, controlled by the LASH_ERROR_FORMAT environment variable or the --error-format CLI flag.

Clear, conversational messages with source location and suggestion:

`lss -la`.sort()
^^^^^^^^
Command 'lss' not found (exit code 127).
Did you mean 'ls'? Check your spelling or install the program.

Single-line compact JSON to stderr, one line per error. Useful for tool integration:

{"type":"cmd_err","expr":"`lss -la`.sort()","step":"lss -la","code":127,"problem":"command not found","suggest":["ls","less"]}

Token-optimized terse format for LLM consumption:

ERR cmd `lss` !found 127 ?ls ?less
Terminal window
# via environment variable
export LASH_ERROR_FORMAT=json
lash script.lash
# via CLI flag
lash --error-format json script.lash

When a functional chain fails, lash identifies the exact step that caused the failure, not just the whole expression:

`cat data.txt`.sort().map(x => x.toNumber()).sum()

If toNumber() fails on a non-numeric line, the error points to the .map(x => x.toNumber()) step, showing the input data and expected vs actual types.

lash uses Levenshtein distance to suggest corrections for misspelled commands and method names.

Command typos:

$ gti status
Command 'gti' not found.
Did you mean 'git'?

In interactive mode, suggestions appear as a navigable list:

KeyAction
Up/DownNavigate suggestions, updating prompt
1-9Jump to numbered suggestion
EnterSubmit selected suggestion
EscapeDismiss suggestions
Any otherDismiss suggestions, type that character

Arguments from the original command are preserved in suggestions.

Method typos:

`ls`.srot()
# Error: unknown method 'srot'. Did you mean 'sort'?

Instead of a raw “Permission Denied,” lash explains which file is restricted and suggests using elevated privileges:

Cannot read '/etc/shadow': permission denied.
Try running with elevated privileges or check file permissions with 'ls -la /etc/shadow'.

The $? variable holds the exit code of the last command:

grep "pattern" file.txt
echo "exit code: $?" # 0 if found, 1 if not found
`curl -f https://example.com/api`.capture
if $? != 0 {
echo "request failed"
}

In functional chains, the exit code reflects the chain outcome. A failed chain step sets a non-zero exit code.

Since lash does not have try/catch, use exit codes and .isSuccess/.isFailure to handle errors:

let result = `make -j8`.capture
if result.isFailure {
echo "build failed:"
(result["stderr"])
exit 1
}
echo "build succeeded"

Check command existence before running:

let check = `which docker`.capture
if check.isFailure {
exit "docker is not installed"
}