Errors

July 10, 2026 ยท View on GitHub

Every mongreldb:: command that talks to the server can throw a Tcl error on failure. The error carries a category in the Tcl errorcode list so you can branch on it with try ... trap without parsing the error message.


The category set

CategoryHTTP statusCause
auth401, 403Missing, malformed, or rejected Authorization header. Bad token or basic-auth credentials.
not_found404Unknown table name, or a row that does not exist.
conflict409Unique constraint violation: duplicate primary key, or a column-level uniqueness/enum violation.
query400, 5xxMalformed request body, unknown column id, a server-side planner/execution error, or a response that exceeded the size cap.
network-The HTTP request itself failed: connection refused, DNS error, timeout, broken pipe.
json-The server returned a response that could not be decoded as JSON when JSON was expected.

Matching with try ... trap

The category is the second element of the errorcode list, under the MONGRELDB prefix:

try {
    mongreldb::put $db orders {1 1 2 Alice}
} trap {MONGRELDB conflict} {e ec} {
    puts stderr "duplicate row, skipping: $e"
} trap {MONGRELDB auth} {e ec} {
    puts stderr "bad credentials: $e"
    exit 1
} trap {MONGRELDB network} {e ec} {
    puts stderr "daemon unreachable, will retry: $e"
} on error {e ec} {
    puts stderr "unexpected: $e ($ec)"
}

The trap pattern {MONGRELDB <category>} matches the prefix and category elements of the errorcode. Use a trailing on error arm as a catch-all for anything you did not anticipate.

Reading the detail

The error message ($e above) is human-readable and includes the server's own error text when the server produced one:

conflict: duplicate primary key value

For server errors the daemon wraps detail in an envelope ({"error":{"message":..., "code":..., "op_index":...}}). The client extracts message for the error string. op_index (when present) identifies which op in a batch transaction triggered the rollback.

Recoverable vs not

CategoryRecoverable?Pattern
networkYes - retry after backoffTransient; the daemon may have restarted.
conflictSometimes - re-read, reconcile, retryThe data changed under you. Re-fetch and decide.
authNo - fix credentials and reconnectStale token, wrong password.
not_foundNo - check the table/row idProgramming error or race.
queryNo - fix the requestMalformed body, bad column id, etc.
jsonNo - protocol mismatchLikely a server version skew.

Retrying safely

For network errors, retry with backoff. If the operation is a write, pass an idempotency key so a replayed request is deduplicated on the server:

proc safe_put {db table cells} {
    set key "put-[clock microseconds]"
    for {set i 0} {$i < 3} {incr i} {
        try {
            return [mongreldb::transaction $db \
                [list [dict create put [dict create table $table cells $cells]]] \
                $key]
        } trap {MONGRELDB network} {e ec} {
            after [expr {200 * (1 << $i)}]
        }
    }
    error "gave up after retries: $e"
}

See transactions.md for more on idempotency keys.

The size cap

The client rejects any response body larger than 256 MB with a query error. This is a guard against runaway queries exhausting memory. If you hit it, narrow your query (add a limit, project fewer columns, or page with SQL LIMIT/OFFSET).

Next steps