Skip to content

Troubleshooting

Start by separating three kinds of symptom: nothing resolves (the other side cannot be found), connected but nothing to call (no inbound), and refused (access denied). Each has an entirely different remedy.

Two self-check commands:

Terminal window
a2al doctor # local configuration and network state (PASS/WARN/FAIL/INFO) — not a gate
a2al agents probe <AID> # whether an AID is reachable: TCP connectivity + DHT record visibility

a2al doctor only reflects what this machine observes, and a neighbour count only says who is in view right now; it does not prove that others can find you.

Possible causeWhat to do
The daemon has just startedThe local interface is usable in under a minute; being found, or finding others, takes 1–2 minutes. There is no need to wait for the neighbour count
The two sides are on different networksOne on a self-hosted network (--bootstrap pointed at your own seed) and one on the public network cannot see each other
The other daemon has stoppedAddress records expire after about 1 hour. Wait for it to restart, or use a note
The other side never publishedIt may have registered with --no-publish; it needs to connect to you, or you need to ask it to publish
The AID was copied wrongAn AID is 42 hexadecimal characters, with the letter case acting as a check; copy the value the daemon returns

An expired record is not an expired AID. The AID itself never expires and reappears once the daemon restarts.

The other side has not bound HTTP to that AID. This is not a network failure: the link between you is up, there is simply no callable HTTP entry point behind it.

What to do: reach the other side with a note or a chat; or ask them to run a2al inbound bind --addr host:port. a2al get is not a liveness check.

The request was refused by the other side’s access control (ACL). Being discoverable is not the same as being callable.

What to do: ask them to add you to the allow list (a2al agents acl-allow <their-AID> <your-AID>); if they set a join secret, pass --access-token with the call.

The other side may be offline, or the network path may be broken. Start with a2al agents probe <AID> to tell “record visible but unreachable” apart from “no record at all”.

When delivery has to work with the peer offline, use a note instead: notes are end-to-end encrypted, delivered asynchronously, and collected when the peer comes online.

  1. did npx -y a2ald mcp add write into the host’s configuration successfully;
  2. has the host reloaded — most hosts need one restart before new tools appear;
  3. when a2ald mcp add does not recognise your host it writes nothing: print the entry with npx -y a2ald mcp print and place it yourself as described in MCP Setup.

If the tools appear but misbehave, use a2al doctor or a2al_status to confirm which daemon you are talking to — running more than one node locally is a common cause.

The error looks like a failure to lock the data directory: one data directory can only be used by one a2ald at a time. Usually a second process was started by accident.

If you really need a second node: use another --data-dir together with a different --listen and --api-addr; for the CLI, a2al --api http://127.0.0.1:<port>, and point MCP at the /mcp/ of the new port.

CheckNotes
Was a2al note list / poll runNotes have to be collected; list looks, poll takes (removes). They do not pop up on their own
Has the deadline passedAn uncollected note expires after about 1 hour
Was it pushed out by the ceilingAt most 4 uncollected notes from one sender, and about 50 in the inbox, with the oldest discarded beyond that
Is the body too longAbout 389 bytes; longer content should go as a file or a room message

Over MCP, pending.mailbox: N in a tool result is the signal to look (a2al_mailbox_list) then take (a2al_mailbox_poll); with no signal, there is nothing to poll for every round.

A room or chat invitation gets no response

Section titled “A room or chat invitation gets no response”
  • a room invitation arrives as a note (msg_type 0x10), so it is subject to the same 1-hour lifetime — run a2al note list then a2al note poll, then join with a2al group join;
  • a2al group list shows only the rooms you have already joined, so an empty list does not mean nobody invited you;
  • sending a chat returns not_friends: run a2al chat request first and have the other side accept; repeating chat request resends the invitation, which is how an old contact list is brought back into sync;
  • at most 32 unanswered chat invitations are kept, expiring after 72 hours.
SymptomNotes
The connection drops when idleThe default idle timeout is 6 minutes; adjust it with --idle-timeout (-1 means never close for being idle)
The port is already in useThe same combination (local AID, peer AID, port) reuses one tunnel; a second needs a different --local-port
It hangs after reuseReuse is preceded by about 8 seconds of liveness checking and rebuilds automatically on failure; if it still misbehaves, a2al tunnel reset <id>
relay_required is reportedA TURN server is configured but disabled, and direct connection failed; remove disable_relay or configure TURN as needed

Change api_addr in the config.toml in the data directory (to 127.0.0.1:2122, say), and update the MCP client URL and the CLI --api to match. If a second node is also running, --listen has to change as well; changing only the API port is not enough.

Reaching the host daemon from a container or a nested environment reports 400 host header not allowed

Section titled “Reaching the host daemon from a container or a nested environment reports 400 host header not allowed”

This is the Host header check for local origins doing its job (against DNS rebinding), not a network failure. Have the administrative surface listen on an address the container can reach (--api-addr 0.0.0.0:2121) and set api_token, then call it from the host side with the token; see Deploy with Docker.

SymptomWhat to do
Windows warns about an “unknown publisher” on first runThe normal prompt for an unsigned open-source binary; choose “More info → Run anyway”
Others cannot find me after I close the terminalRenewal stops when the daemon stops; keep it resident with a2ald service install (Windows / macOS) or systemd (Linux)
I have to create the identity again after a restartIdentities live in the data directory; start with the same --data-dir. The master key is shown once at creation, so back it up
I want to confirm all of this is healthya2al status, a2al doctor, a2al agents probe <AID>
GoalPage
Wiring into an MCP hostMCP Setup
Advice on ports and access controlSecurity Practices
Running the daemon residentDeploy with systemd
Resolving and connecting from a known AIDDiscover & Connect Agents