Skip to main content
Mirage names a failure once and each surface reports it in its own form. A file call fails with a POSIX condition, a shell line ends with an exit status and a GNU-worded line on stderr, and HTTP, RPC, MCP and the kernel mounts carry one of those two.

File calls

A file call (read, write, stat, readdir, rename, …) names its failure with one of these conditions, whatever the backend. A service’s own error becomes the condition it means, such as an object that is not there becoming ENOENT. One that means none keeps its own words in an exception and in a shell diagnostic. HTTP answers it 500, and RPC -32603, with detail set to internal server error and no errno, since those words can carry credentials or host paths; they stay in the server’s logs. Each surface carries the condition its own way:

Shell lines

A line that runs to its end answers exit_code, stdout and stderr. A non-zero status is the line’s result, not a failed call: HTTP answers 200, RPC a result, and MCP sets isError. Canceling the request is a failed call instead: HTTP answers 499 and RPC the error -32800. A command’s stderr follows GNU coreutils, and its status is the one the real command exits with. These statuses come from the shell itself:

Service errors

A command that reaches a service through a mount reports the service’s failure as the condition it maps to, or in the service’s own words after the command’s name. An account CLI such as gh or ntn reports a service error the way the real CLI does, with its wording and exit status.