Troubleshooting
Diagnose CLI problems with machinemail doctor and --verbose, and fix the common errors - no API key, a rejected key, an unreachable API, a broken config file, wait timeouts, deletes that need --yes and sign-in codes that expire.
Start with doctor, then look up the error below. Every error goes to stderr with a hint, and the exit code says what kind of failure it was.
machinemail doctor
doctor runs every check and reports each one, without stopping at the first failure:
A failing check says how to fix it:
| Check | What it looks at |
|---|---|
| Config file | The file exists, parses, and is not readable by other users. |
| Profile, API | Which profile and base URL are in use, and where each came from. Warns about plain http:// to a remote host. |
| API key | A key is set, and whether MACHINEMAIL_API_KEY shadows the profile’s. |
| Connectivity | GET /health answers. |
| API ready | GET /health/ready answers. |
| Key accepted | GET /v0/auth/me accepts the key, and what it is scoped to. |
| Clock | Skew against the API’s Date header. Over 30 seconds warns, over 5 minutes fails. |
| CLI | Version, runtime and target, and the update check. |
doctor exits with the code of the first failure (7 config, 6 network, 3 auth, 1 other) or 0; warnings do not fail it. --offline skips the checks that call the API, --profile checks another profile, and --json gives { ok, checks: [{ id, label, status, detail, hint? }] }:
See the requests
-v/--verbose logs each request and response to stderr: method, URL, status, timing and bodies. API keys, webhook secrets, claim tokens and agent tokens are redacted, so you can paste the log into an issue.
When you report a problem, include machinemail version --json and the doctor --json output.
Common errors
No API key (exit 3)
The profile in use has no key and none was given. Run machinemail login, set MACHINEMAIL_API_KEY, or pass --profile if the key is saved under another profile name (machinemail profiles list).
Missing or invalid API key (exit 3)
The API rejected the key: it was revoked, mistyped, or belongs to another API. machinemail whoami shows which key is in use and where it came from; a stale MACHINEMAIL_API_KEY in your shell overrides the profile’s key. A 403 means the key is valid but lacks the permission or scope for that call, for example an inbox-scoped key used on another inbox.
Could not reach the API (exit 6)
Check the base URL with machinemail config get base_url --json (it says where the value came from), and that the host resolves from where the CLI runs. Behind a proxy, set HTTPS_PROXY. Failed GET, PUT and DELETE requests are already retried three times before this error.
Could not read the config file (exit 7)
The config file is not valid JSON, usually after a hand edit. Fix it, or move it aside and sign in again. Use config set and profiles to change it rather than an editor.
Unknown command or flag (exit 2)
Nothing was sent. The hint suggests the closest command, action, flag or enum value. Command flags go after <resource> <action>; machinemail <resource> <action> --help lists them.
Missing --from or --inbox (exit 2)
send, wait and read need an inbox. Pass it, or set a default with MACHINEMAIL_INBOX. An inbox-scoped key or a profile from register provides one automatically.
A delete says add --yes (exit 2)
Deletes ask for confirmation on a terminal. In a script, a pipe, or with CI set, there is nobody to ask, so pass --yes.
wait timed out (exit 8)
- The email arrived before
waitstarted: add--since 5m. wait --otpskipped the message because its sender did not authenticate: check withmachinemail messages list <inbox>andmachinemail read <message-id>. If the sender is a test system without SPF or DKIM, add--allow-unauthenticated.--fromor--subjectdid not match:--fromis an exact address or a domain and its subdomains;--subjectis a case-insensitive substring.
The sign-in code expired (exit 8) or was denied (exit 3)
Sign-in codes are valid for 10 minutes and work once. Run machinemail login again for a new code. If you cannot reach a browser that is signed in to MachineMail, create a key on the dashboard and use machinemail login --paste or --key - instead.
Rate limited (exit 5)
The API answered 429 after the CLI’s own retries, which honor Retry-After. Slow down, or raise MACHINEMAIL_MAX_RETRIES for a batch job. A sandbox agent from register has daily caps on messages and different recipients until it is claimed; the error message states them. See Rate limits.
Warning about --api-key
The command still runs. Pass the key through the environment, a profile, or --api-key - on stdin to silence it.
Garbled output or no color
Set NO_COLOR=1 or pass --no-color for terminals that do not render color, and --color to force it in one that is not detected. Tables use the width the terminal reports; where it reports none (some CI logs), set COLUMNS. For scripts, use --json and never parse tables.