Troubleshooting

Common issues and solutions for Self Agent ID integration

userDefinedData encoding fails

This is the #1 integration mistake.

The Self SDK passes userDefinedData as a UTF-8 string, not raw bytes. Each position uses the ASCII character — '0' (0x30), not 0x00.

// WRONG — raw byte value
bytes32 data = bytes32(uint256(0));

// CORRECT — ASCII character
bytes32 data = bytes32(bytes1(uint8(uint8(bytes1("0")))));

Use bytes32(bytes1(uint8(x))) for byte positioning in bytes32.

triangle-exclamation

"Agent not verified" when querying

Possible causes:

  1. Wrong chain ID — Are you querying the right network? Mainnet is 42220, testnet is 11142220.

  2. Wrong registry address — Each network has its own registry. See Smart Contracts for addresses.

  3. Agent not yet registered — Registration requires the Self app callback to complete. Poll with self_check_registration or the REST API status endpoint.

  4. Agent was deregistered — The soulbound NFT was burned. Re-registration is needed.

  5. Proof expired — The agent's human proof has passed its validity window. Check isProofFresh(agentId) — if it returns false, the agent must re-authenticate by scanning their passport again.

Agent proof expired

If isProofFresh() returns false but hasHumanProof() returns true:

  • The proof validity window has elapsed (default: 1 year or document expiry, whichever is sooner)

  • The soulbound NFT is NOT burned — it remains as a historical record

  • The agent must re-authenticate via the Self app to restore fresh status

  • SDK verifiers automatically reject expired proofs with a descriptive error

Registration callback never arrives

Check these:

  1. SELF_ENDPOINT type mismatch — Use celo for mainnet, staging_celo for testnet. If set wrong, the Self app sends the callback to the wrong network.

  2. .env.local key must be lowercaseNEXT_PUBLIC_SELF_ENDPOINT (not NEXT_PUBLIC_Self_Endpoint). Environment variable names are case-sensitive.

  3. Callback URL not reachable — If running locally, ensure the callback port is accessible. The CLI binds to 127.0.0.1 by default.

  4. Session expired — Sessions have a 30-minute TTL. Start a new registration if expired.

Signature verification fails

Common causes:

  1. Timestamp drift — The verifier rejects signatures older than 5 minutes (default). Ensure client and server clocks are in sync.

  2. Body encoding — The signature covers keccak256(timestamp + METHOD + path + bodyHash). If the body is modified in transit (e.g., by a proxy re-serializing JSON), verification fails.

  3. Path vs full URL — The SDK signs the URL path (e.g., /api/data), not the full URL. Ensure your verifier extracts the path correctly.

  4. Wrong private key — The signing key must match the registered agent address.

Wrong chain ID

circle-exclamation
Network
Chain ID
RPC

Celo Mainnet

42220

https://forno.celo.org

Celo Sepolia

11142220

https://forno.celo-sepolia.celo-testnet.org

Foundry build fails

If you see errors about PUSH0 or unsupported opcodes:

Add to foundry.toml:

Provider verification untrusted

If agents pass isVerifiedAgent() but you don't trust the proof source:

Without requireSelfProvider(), any approved provider's proofs are accepted. Self Protocol's provider is the only one currently deployed, but this guard protects against future third-party providers.

WebAuthn / passkey errors

Firefox blocks WebAuthn on http://localhost. Use one of:

  • Chrome on http://localhost (Chrome allows it)

  • HTTPS with a local cert (e.g., mkcert)

  • Deployed URL with HTTPS

This only affects smart wallet mode (passkey-based registration).

Smart wallet not gasless on testnet

Smart wallet mode is counterfactual only on testnet — the smart account address is computed but not deployed, so gasless transactions aren't available.

On mainnet, the Pimlico paymaster sponsors gas for registration transactions, enabling full gasless UX.

Blockscout / Celoscan verification issues

  • Blockscout does not require an API key for contract verification.

  • Celoscan — use the Sourcify verifier (not the etherscan verifier). The Celoscan API endpoint is flaky; Sourcify is more reliable.

"InvalidIdentityCommitmentRoot" error

You're using the wrong network. Real passports only work on mainnet (Celo, chain ID 42220). Mock documents only work on testnet (Celo Sepolia, chain ID 11142220). Make sure your registration network matches your document type.

A2A endpoint unreachable

If other agents cannot reach your A2A endpoint:

  1. Endpoint not registered — The agentURI metadata must include the A2A endpoint URL. Check that setAgentURI() was called after registration.

  2. Firewall / NAT — Your A2A server must be publicly reachable. If running locally, use a tunnel (e.g., ngrok) and register the tunnel URL as your endpoint.

  3. TLS required — A2A endpoints must be served over HTTPS. Plain HTTP connections are rejected by most agent runtimes.

  4. CORS misconfigured — If the calling agent is browser-based, your A2A server must return appropriate Access-Control-Allow-Origin headers.

  5. Wrong path — The default A2A path is /.well-known/agent.json for the agent card. Ensure your server serves the agent card at that path and the url field inside it points to the correct task endpoint.

MCP "no identity" error

If MCP tools that require identity (sign, fetch, get identity) fail:

  • SELF_AGENT_PRIVATE_KEY is not set in your MCP config

  • Query tools (self_lookup_agent, self_verify_agent, self_list_agents_for_human) work without a key

  • Set the key in your MCP config env block to enable full mode

Last updated