Troubleshooting
Each entry is what you see, why, and what to do. Error bodies are
{ status, error, message, details? }; the error code is what to search for.
See the node API reference for the full list.
merod will not start
Section titled “merod will not start”| You see | Cause | Fix |
|---|---|---|
the node's id is not set / the node's public URL is not set |
--node-id or --public-url missing from flags, environment and file |
Set them; init needs both. |
no data directory: --data-dir DIR (or --node NAME) |
run without --node and without --data-dir |
Pass one. |
peer must be id=url |
A --peers entry without = |
--peers 1=https://n1/,2=https://n2/. |
a TDX node takes its storage key from mero-kms only |
--storage-key or --storage-key-file without --dev |
Use --kms-url with --kms-identity, or add --dev on a development machine. |
no storage key: pass --kms-url with --kms-identity |
TDX mode with no key source | As it says. |
mero-kms needs both --kms-url and --kms-identity |
One of the two | Give both. |
a TDX node needs MERO_TEE_VERSION and MERO_TEE_PROFILE |
Not running in a mero-tee image, or the image did not set them | Run in the image, or set --tee-release/--tee-profile (or --peer-profiles); for a local node use --dev. |
TDX quote: … |
TDX mode outside a TD | Use --dev outside a TD. |
… exists: merod --node NAME config ... changes it |
A second init |
config to change it, init --force to replace it. |
config.toml: unknown field … |
A typo, or a key this release does not have | Remove it; keys are kebab-case and listed in Configuration. |
Address already in use |
Another process on --listen (often a running merod local on 2501–2503) |
Stop it or choose another port. |
the local cluster did not form within 20 s |
merod local nodes could not reach each other |
Check the ports are free; try --fresh. |
meroctl cannot reach or trust the node
Section titled “meroctl cannot reach or trust the node”| You see | Cause | Fix |
|---|---|---|
which node? --api URL, --node ALIAS, or save one |
No node chosen | meroctl node add NAME URL, or --api. |
real quote refused: this client trusts no TD image |
A real node, and no --tee-profiles |
Pass --tee-profiles PROFILE (or CALIMERO_TEE_PROFILES). |
| a refusal naming a mock quote | A development node, without --allow-mock |
--allow-mock, or node add NAME URL --allow-mock. |
a refusal naming the release or min version |
The node’s release is older than --min-release (default 2.3.109) |
Upgrade the node, or lower the floor knowingly. |
| a refusal naming a debug profile | The node runs a debug image | Only for debugging: --allow-debug-profiles. |
a file passkey is for development clusters (--allow-mock) |
login against a real cluster |
Sign in in a browser and use an API key (--api-key). |
Sign-in and credentials
Section titled “Sign-in and credentials”| You see | Cause | Fix |
|---|---|---|
400 UNKNOWN_CHALLENGE (“start again on this node”) |
begin and finish reached different nodes, or the challenge was used |
Keep a ceremony on one node: session affinity on the balancer, or one node URL. |
400 EXPIRED_CHALLENGE |
More than 5 minutes between begin and finish |
Start again. |
401 PASSKEY_UNKNOWN_HERE |
The browser offered a passkey from another cluster (clusters share an rp-id), or one that was removed | Sign up on this cluster, or open the app from the link for the cluster the account is on; the passkey’s name in the password manager names its cluster. |
400 BAD_REGISTRATION or a refused assertion |
Wrong origin or relying party | The page’s origin must be in --origins; --rp-id must be its domain or a parent of it. |
401 UNAUTHENTICATED “token signed with an unknown key” |
The node has not applied the session key yet, or the token is from another cluster | Retry; check you are talking to the cluster that issued it. |
401 “refresh token already used; the session is revoked” |
A refresh token was presented twice | Sign in again; find who else holds the token. |
401 “the passkey this session used was removed” |
The device was revoked | Sign in with another passkey. |
403 “this needs a passkey session, not an API key” |
Managing credentials, approvals or upgrades with an API key | Use a passkey session. |
403 “this API key is scoped; installing code …” |
A scoped or read-only key installing or creating apps | Use an unscoped key or a session. |
403 “a session opened on an app’s frontend can use that app only” |
An app-bound session doing account work | Do it on the cluster’s own page. |
403 “the Ops API is disabled on this node” |
No --ops-token / --ops-token-sha256 |
Configure one and restart. |
403 “operator credential required” |
Wrong ops token | Check the token against the configured hash. |
412 CONFIRM_REQUIRED |
The action needs a passkey assertion | A browser or SDK client answers it; meroctl needs --dev-passkey on development clusters. |
Calls, reads and leaders
Section titled “Calls, reads and leaders”| You see | Cause | Fix |
|---|---|---|
503 UNAVAILABLE “no leader yet; retry” |
An election is under way, or a group lost its majority | Retry after a few seconds; if it persists, check that a majority of the group’s replicas (or the system voters) is up. |
Every node is up but the system group keeps electing (the term climbs; the leader logs timeout after 200ms when AppendEntries to a peer, and Quote parsed successfully repeats without Overall verification: PASSED) |
merod before this fix attested a peer inside each Raft RPC and dropped the attestation with the RPC, so on TDX (about a second per attestation) the channel never opened | Run a merod with the fix; nothing on disk needs changing. |
503 UNAVAILABLE “the system group did not commit this write in 10 s (leader …, voters […], learners […], behind the leader: […])” |
The system group has a leader but cannot commit: too few voters answer, or a voter change waits on members that do not | The members listed behind the leader are the ones not answering: check they run and reach the leader on the cluster port. The write may still apply once the group commits, so look before repeating it. |
503 NOT_CAUGHT_UP |
A stale read with minIndex the replica has not reached in 2 s |
Retry, lower minIndex, or read from the leader. |
421 NOT_LEADER on ops move |
Sent to a follower | Send it to details.leaderUrl; meroctl ops move does this itself. |
404 NOT_FOUND “no such app” |
The app does not exist, or the caller does not reach it | Check the id or alias, and the app’s access. |
403 “read-only in this team: the call would write” |
A read-only team member called a method that is not a view | Change their role, or call a view. |
422 APP_ERROR |
The app’s method returned an error | The app’s own logic; see message and details. |
413 ARGS_TOO_LARGE |
A call’s arguments over the node’s argument cap, refused before the call runs | Send less per call; pass large content as a blob and its id. |
413 TOO_LARGE |
A call’s log entry over 1 MiB, or a bundle over 16 MiB | Write less per call; keep large content in blobs. |
429 RATE_LIMITED on events |
The node has 4096 open streams | Use another node, or close idle streams. |
Installs, apps and upgrades
Section titled “Installs, apps and upgrades”| You see | Cause | Fix |
|---|---|---|
403 “this node takes signed packages only” |
Raw WASM on a node without --allow-unsigned-bundles |
Install a signed .mpk. |
400 BAD_PACKAGE |
Signature, digest, pinned signer or minRuntimeVersion check failed |
Rebuild and sign with mero-sign (scripts/pack-component.py); a package keeps its first release’s signer. |
400 UNSUPPORTED_BUNDLE |
The bundle is a WASM core module (an SDK 0.12 app), which this node no longer runs | Rebuild the app with calimero-sdk into a calimero:app component. |
410 UNSUPPORTED_ENGINE |
The app is an SDK 0.12 (wasmer) app from before the engine was removed: listed, but nothing runs | Rebuild it with calimero-sdk, create it again, and delete the old instance. |
400 NO_REGISTRY |
PACKAGE@VERSION with no --registry-url |
Configure the registry (on a --dev cluster you may upload the .mpk instead). |
403 UPLOADS_DISABLED |
An uploaded .mpk on a node without --dev |
Publish it to the registry and install PACKAGE@VERSION. |
422 INIT_FAILED |
The app’s init failed; no instance is left behind |
Check initArgs. |
422 UPGRADE_FAILED |
The migration did not run or its check failed | See details; the app stays on its bundle. |
| an upgrade refused as a downgrade, jump or missing edge | The ABIs give no single migration step | Add the #[app::migrate] edge, or upgrade one state version at a time. |
| uninstall refused | An app still runs that release | Upgrade or delete those apps first. |
429 QUOTA_EXCEEDED |
An account quota | meroctl ops quotas; raise with ops set-quotas. |
403 “deployed with … decided by its operator” / “by each app’s owner” |
The other party holds that decision | See Governance; it cannot change after genesis. |
403 “node N runs release …, which this app’s owner has not approved” |
A replica move onto a node on an unapproved release | Get the release approved first. |
an app’s outbound request refused (NotApproved, AwaitingApproval) |
No [outbound] policy, the host is not allowed, or the prefix is not approved for the publisher |
Configure [outbound]; the holder of outbound approvals approves the prefix. |