Error Diagnostics

Every error in mino produces a structured diagnostic: a plain map with stable keys, a classified error code, source location, and a human-readable message. The same model serves the REPL, embedded hosts, and user code.

What You See

When an error occurs in the REPL or a script, mino renders a diagnostic with the error code, message, source file, line, column, and a snippet of the source with a caret pointer:

error[MTY001]: count: expected a collection, got int
  --> app.clj:18:3
   |
 18 |   (count 42)
    |   ^

Reader errors show the exact position:

error[MRE001]: unterminated string literal
  --> app.clj:7:8
   |
  7 | (def y "unterminated
   |        ^

Errors Are Data

In catch handlers, the exception value is always a map with these keys:

KeyTypeMeaning
:mino/kindkeywordCategory: :reader, :syntax, :eval/type, :eval/arity, :eval/bounds, :user, etc.
:mino/codestringStable error code, e.g. "MTY001"
:mino/phasekeywordProcessing phase: :read, :eval
:mino/messagestringHuman-readable primary message
:mino/dataanyThe original thrown value (for user exceptions)

Example: catching a type error and inspecting it.

(try
  (count 42)
  (catch e
    (println (:mino/kind e))    ;; :eval/type
    (println (:mino/code e))    ;; "MTY001"
    (println (:mino/message e)) ;; "count: expected a collection, got int"
    ))

throw and catch

(throw x) accepts any value. The catch handler always receives a diagnostic map, regardless of what was thrown. The original value is accessible via (ex-data e):

(try
  (throw "oops")
  (catch e
    (println (ex-data e))    ;; "oops"
    (println (ex-message e)) ;; "oops"
    (println (error? e))     ;; true
    ))

If you throw an ex-info map, ex-data and ex-message extract the payload transparently:

(try
  (throw (ex-info "not found" {:code 404}))
  (catch e
    (println (ex-data e))    ;; {:code 404}
    (println (ex-message e)) ;; "not found"
    ))

Helper Functions

FunctionDescription
(error? x)True if x is a map with :mino/kind
(ex-data e)Extract the data payload from a diagnostic map or ex-info
(ex-message e)Extract the message from a diagnostic map or ex-info
(last-error)Return the last diagnostic map, or nil
(ex-info msg data)Create an exception map for throwing

Error Code Catalog

Every error has a stable code that can be matched programmatically. Codes are grouped by prefix:

PrefixCategoryExamples
MREReaderUnterminated string, unexpected delimiter, unterminated collection
MSYSyntaxMalformed def, fn, let special forms
MNSName resolutionUnresolved symbol, missing namespace alias
MARArityWrong number of arguments
MTYType mismatchOperation received unsupported value type
MBDBoundsIndex out of range
MCTContractPrecondition or invariant violation
MHOHostCapability denied, host callback failure
MIOI/Oslurp, spit, sh, file-system access failures
MOMOut of memoryAllocator exhausted during a user-visible computation (e.g. bignum arithmetic)
MOVOverflowInteger overflow on + / - / * / inc / dec when the bignum-promoting variant (+' etc.) was not used
MLMLimitStep limit, heap limit, recursion depth exceeded
MUSUserUser-thrown exception
MINInternalRuntime invariant violation or unhandled internal-state error

C API

Embedders have structured access to the last error:

/* Backward-compatible string access */
const char *mino_last_error(S);

/* Structured diagnostic (internal fields) */
const mino_diag *mino_last_diag(S);

/* Diagnostic as a mino map with :mino/* keys */
mino_val *mino_last_error_map(S);

/* Render to buffer in compact or pretty mode */
int mino_render_diag(S, diag, MINO_DIAG_RENDER_PRETTY, buf, sizeof(buf));

Existing code using mino_last_error() continues to work unchanged. The string is rendered from the structured diagnostic internally.