Exit Codes¶
Complete reference for Kelora's exit codes and their meanings.
The model in one line¶
Kelora exits non-zero when it couldn't do the job you asked — not because the data was messy.
The model turns on gates vs. transforms:
- Gates — parse and each
--filterstage — must work. If a gate never once succeeds (no line parses, or a filter errors on every event it sees and so never selects anything), the output is empty or meaningless — a broken command — so the run exits1. A gate erroring on only some records is recovered (exit0). Each filter is gated individually: a working first filter does not mask a completely broken second one. - Transforms — exec — are best-effort. A failing
--execrolls back to the original event and emits it, so exec errors are reported but never fail the run on their own, even when they hit every event.
Structural failures (a named input that won't open) and --assert violations
fail in any mode. --strict escalates: any single parse/filter/exec error fails
immediately, and --assert adds explicit data-quality gates.
This is independent of output flags: the signal is computed in the always-on
tracker, so --metrics, --drain, -q, and --no-diagnostics all preserve
the exit code.
Standard Exit Codes¶
Kelora uses standard Unix exit codes to indicate success or failure:
| Code | Name | Meaning | Cause |
|---|---|---|---|
0 |
Success | The run did its job | Clean processing, or recovered errors (some lines skipped, exec transforms rolled back) |
1 |
General Error | The run couldn't do the job | A gate that never succeeded (every line fails to parse, or a filter errors on every event), an --assert violation, a file that couldn't be opened, or any strict-mode error |
2 |
Usage Error | Invalid command-line usage | Invalid flags, incompatible options, configuration errors |
Signal Exit Codes¶
When Kelora is interrupted by signals:
| Code | Signal | Meaning |
|---|---|---|
130 |
SIGINT | Interrupted by Ctrl+C |
134 |
SIGABRT | Internal thread panic (a bug — please report) |
141 |
SIGPIPE | Broken pipe (normal in Unix pipelines) |
143 |
SIGTERM | Terminated by system or user |
Exit code 134 only appears on an unexpected internal panic in one of Kelora's
processing threads (reader, worker, or sink). The release binary is built with
panic = "abort", so such a panic aborts the process immediately rather than
unwinding. These are always bugs — the same conditions previously terminated the
run with exit 1/101; only the reported code changed. Please report any
occurrence.
Exit Code 0: Success¶
Indicates the run did its job. The work you asked for happened, even if some individual records were skipped or rolled back along the way.
Important: Exit 0 is not "zero errors" — it's "the job got done". Filtering
events is not an error (filtering everything still exits 0). Recovered
per-record errors — a few unparseable lines among good ones, a --filter/--exec
that errors on some events — are reported as diagnostics but keep exit 0,
because the stage still succeeded on other records. To fail on any such error,
use --strict; to fail on explicit data-quality rules, use --assert.
# Returns 0 - filtering is not an error
kelora -j app.log --levels critical
echo $?
0
# Returns 0 - some lines failed to parse, but others succeeded (recovered)
printf '{"ok":1}\nNOT JSON\n{"ok":2}\n' | kelora -j
echo $?
0
# Returns 1 - NO line parsed: the format is wrong, so the run couldn't do its job
printf 'plain one\nplain two\n' | kelora -j
echo $?
1
Exit Code 1: The run couldn't do the job¶
Indicates the run failed to do what was asked. Common causes:
| Cause | Meaning | Example |
|---|---|---|
| Parse gate failed | Every line failed to parse — the format is wrong or the input is unusable | kelora -j on plain-text logs |
| Filter gate failed | A --filter stage errored on every event it saw, so it never selected anything (each filter is its own gate, even behind other filters) |
--filter 'status >= 500' (missing e.) |
| Assertion failures | --assert expressions evaluated to false (an explicit data-quality gate) |
Missing required fields |
| File I/O failures | A named input file failed to open or decompress | Permission denied, file not found |
| Strict-mode errors | Any parse/filter/exec error while --strict was enabled |
Missing field access, type errors |
Parse and each --filter stage are gates: a gate that errored on some
records is recovered (exit 0); the same gate erroring on every record it
saw means it never once worked, which is a broken command (exit 1). --exec is not a gate —
it's a best-effort transform that rolls back on error and never fails the run on
its own (use --strict/--assert).
Resilient Mode (Default)¶
Gate errors are recorded but processing continues. They affect the exit code only when the gate never succeeds; exec errors never affect it:
# Recovered: a field-name typo in an EXEC errors on every event, but exec rolls
# back and emits the original events -> exit 0 (use --strict to fail)
kelora -q -j app.log --exec 'e.x = e.valeu.to_int()' # typo, but best-effort
echo $?
0
# Broken gate: a field-name typo in a FILTER errors on every event, so it never
# selected anything -> exit 1, even without --strict
kelora -q -j app.log --filter 'status >= 500' # should be e.status
echo $?
1
For automation, use --strict to fail on the first parse/filter/exec error,
and --assert to fail on explicit data-quality requirements.
Strict Mode¶
Processing aborts immediately on first error with --strict:
kelora -j --strict app.log
# ... aborts on first parse/filter/exec/file error ...
echo $?
1 # Processing aborted
# With multiple files, strict mode aborts on first file failure
kelora -j --strict good.log missing.log another.log
⚠️ Failed to open file 'missing.log': No such file or directory
echo $?
1 # Aborted immediately, another.log not processed
Examples¶
# Parse error
echo '{invalid json}' | kelora -j
# Strict-mode filter error
kelora -j --strict app.log --filter 'e.missing_field.to_int()'
# Strict-mode exec error
kelora -j --strict app.log --exec 'e.result = e.invalid.to_int()'
# Assertion failure
kelora -j app.log --assert 'e.has("user_id")'
# File I/O error (some files failed)
kelora -j good.log missing.log
# All return exit code 1
Exit Code 2: Usage Errors¶
Indicates command-line usage errors before processing begins:
| Error Type | Example |
|---|---|
| Invalid flags | kelora --invalid-flag app.log |
| Missing arguments | kelora --filter (no expression provided) |
| Incompatible flags | kelora -I helper.rhai --filter 'e.level == "ERROR"' |
| Invalid configuration | kelora --config-file invalid.ini app.log |
| No input provided | kelora (no files + stdin is TTY) |
Note: File I/O failures (unable to open files) are processing errors (exit 1), not usage errors, regardless of how many files fail. This is consistent with standard Unix tools like cat, tail, and head.
# File I/O failures are always exit 1
kelora -j nonexistent.log
⚠️ Failed to open file 'nonexistent.log': No such file or directory
echo $?
1 # Processing error, not usage error
# Even if all files fail
kelora -j missing1.log missing2.log
⚠️ Failed to open file 'missing1.log': No such file or directory
⚠️ Failed to open file 'missing2.log': No such file or directory
echo $?
1 # Still processing error (like parse errors)
# Usage error (invalid filter-stage include file)
kelora -I helper.rhai --filter 'is_error(e.level)' app.log
⚠️ --include file 'helper.rhai' cannot contain statements when used with --filter; only function definitions are allowed
echo $?
2 # Usage error
Mode Interactions¶
Processing Modes¶
| Mode | Behavior | Exit Code 1 Timing | Use Case |
|---|---|---|---|
| Resilient (default) | Continue on recovered runtime errors | At end only for unrecovered failures | Production, exploratory analysis |
Strict (--strict) |
Abort on first error | Immediately on first error | Validation, fail-fast |
Parallel (--parallel) |
Same as sequential | Same as non-parallel | Performance (exit code behavior unchanged) |
Quiet Modes¶
Exit codes are preserved under all quiet/silent combinations. Use the new toggles to control output without changing exit semantics:
-q/--quiet: suppress events only.--no-diagnostics: suppress diagnostics and summaries (fatal line still emitted).--silent: suppress pipeline terminal emitters (events/diagnostics/stats/terminal metrics); script output still allowed; metrics files still write.-m/--metrics/-s/--stats: data-only modes that already suppress events (no need for-q) and script output while emitting the selected channel.
Using Exit Codes in Scripts¶
Comprehensive Example¶
#!/bin/bash
# Production log processing script
# Check for usage errors first
if ! kelora -j --strict app.log > /dev/null 2>&1; then
exit_code=$?
case $exit_code in
1)
echo "✗ Parse errors detected, check log format"
kelora -j --verbose app.log 2>&1 | grep "error:" | head -5
exit 1
;;
2)
echo "✗ Usage error, check command syntax"
exit 2
;;
130)
echo "⚠️ Interrupted by user"
exit 130
;;
141)
# SIGPIPE is normal in pipelines
exit 0
;;
*)
echo "✗ Unknown error (exit code: $exit_code)"
exit $exit_code
;;
esac
fi
# Process validated logs
if kelora -j app.log --levels error,critical -F json > errors.json; then
echo "✓ No errors found"
else
echo "✗ Processing failed"
exit 1
fi
Common Patterns¶
# Basic validation
kelora --silent -j --strict app.log && echo "✓ Valid" || echo "✗ Invalid"
# Ignore SIGPIPE in pipelines
kelora -j large.log | head -n 10 || [ $? -eq 141 ]
# CI/CD validation
kelora -j --strict logs/*.json > /dev/null || {
echo "✗ Log validation failed"
exit 1
}
# Check for critical events
if ! kelora -q -j app.log --levels error,critical; then
echo "✗ Found critical errors"
exit 1
fi
# Validation loop
for file in logs/*.json; do
kelora -j --strict "$file" > /dev/null 2>&1 || {
echo "✗ Invalid: $file"
exit 1
}
done
Makefile Integration¶
.PHONY: check-logs
check-logs:
@kelora -j logs/*.json --levels error || \
(echo "Errors found in logs" && exit 1)
.PHONY: validate-logs
validate-logs:
@kelora -j --strict logs/*.json > /dev/null || \
(echo "Log validation failed" && exit 1)
Troubleshooting¶
Exit Code 1 When Expecting 0¶
Problem: Getting exit code 1 but don't see errors.
Solution: Use --verbose to see all errors, or check stats:
Exit Code 141 (SIGPIPE)¶
This is normal in pipelines when downstream commands close early:
kelora -j large.log | head -n 10
# Exit code 141 is expected and normal
# Ignore SIGPIPE if needed
kelora -j large.log | head -n 10 || [ $? -eq 141 ]
Exit Code 2 with Valid Syntax¶
Check:
- File exists and is readable:
ls -l app.log - Permissions are correct:
stat app.log - Configuration file is valid
- Try ignoring config:
kelora --ignore-config -j app.log
Different Exit Codes in CI vs Local¶
Possible causes:
- Different file permissions/paths
- Different configuration files
- Environment variables
Solution: Test with same conditions:
See Also¶
- Error Handling - Error handling modes and strategies
- CLI Reference - Complete flag documentation
- Quiet/Silent Controls - Suppressing output for automation