troubleshooting.md

Troubleshooting

Diagnose MachineMail CLI problems with doctor and --verbose, and fix common errors: missing or rejected keys, an unreachable API, broken config and timeouts.

Source: https://machinemail.dev/docs/cli/troubleshooting

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:

machinemail doctor
MACHINEMAIL doctor

OK    CONFIG FILE   /home/ada/.config/machinemail/config.json (0600)
OK    PROFILE       default (profile)
OK    API           https://api.machinemail.dev (profile)
OK    API KEY       mm_live_…hdYv (profile)
OK    CONNECTIVITY  GET /health 200 in 3ms
OK    API READY     ready
OK    KEY ACCEPTED  organization key, organization org_01m4gnem700000j9kk6vas9c0c
OK    CLOCK         in sync with the API
OK    CLI           0.1.0 (bun 1.4.2, linux-x64); update check off

No problems found  9 ok

A failing check says how to fix it:

WARN  CONFIG FILE   /home/ada/.config/machinemail/config.json (not created yet)
                    Run `machinemail login` to create it.
OK    PROFILE       default (default)
OK    API           https://api.machinemail.dev (default)
FAIL  API KEY       none
                    Run `machinemail login`, or set MACHINEMAIL_API_KEY.
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? }] }:

machinemail doctor --json | jq '.checks[] | select(.status != "ok")'

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.

machinemail inboxes list --verbose 2> requests.log

When you report a problem, include machinemail version --json and the doctor --json output.

Common errors

No API key (exit 3)

{"error":{"type":"cli","message":"No API key"},"hints":["Run `machinemail auth login`, or set MACHINEMAIL_API_KEY."]}

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)

{"error":{"type":"unauthorized","message":"Missing or invalid API key"},"status":401}

The API rejected the key: it was revoked or mistyped. 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)

{"error":{"type":"cli","message":"Could not reach https://api.machinemail.dev: host not found"},"hints":["Check the base URL (--base-url, MACHINEMAIL_BASE_URL or the profile) and your connection."]}

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)

{"error":{"type":"cli","message":"Could not read /home/ada/.config/machinemail/config.json: JSON Parse error: Expected '}'"},"hints":["Fix the JSON or delete the file and run `machinemail auth login` again."]}

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)

{"error":{"type":"usage","message":"Unknown flag --usernam"},"hints":["Did you mean --username?"]}

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)

{"error":{"type":"usage","message":"Missing --from"},"hints":["Pass the inbox address, set MACHINEMAIL_INBOX, or use a profile from `machinemail register`."]}

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)

{"error":{"type":"usage","message":"Delete inbox support-agent@machinemail.dev: add --yes to confirm"},"hints":["There is no terminal to ask on, so nothing was sent."]}

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)

{"error":{"type":"cli","message":"No matching message arrived in 0:05"},"hints":["Raise --timeout, or use --since if the email was sent before the wait started."]}

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

machinemail: warning: a key passed as --api-key <key> is visible to other local processes and lands in shell history; prefer MACHINEMAIL_API_KEY, a profile (machinemail login), or --api-key - to read it from stdin

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.