Guides

Troubleshooting

Troubleshooting common agdb issues: CORS, setup, clients, cluster, auth

Getting cross-origin (CORS) errors when connecting to the agdb_server

CORS error can happen even locally when running the server and connecting to it using raw IP address (e.g. 127.0.0.1). Try running the server and binding it to localhost (default) or another DNS name instead.

Database fails to open or appears corrupted

When a database is opened the WAL (write-ahead log) file is replayed to repair any incomplete transactions from a previous crash. If the main database file (.agdb) or its WAL (.agdb.wal) are missing or truncated (e.g. disk full during a write), the database may fail to load.

Steps to try:

  1. Make sure both the .agdb and .agdb.wal files are present and not zero-length.
  2. If only the WAL is missing the database will still load, but you may have lost the last uncommitted transaction.
  3. Restore from a backup if available: use /api/v1/db/{owner}/{db}/restore (server) or copy the backup file manually (embedded).
  4. If you run on a network filesystem (e.g. WekaFS), consider enabling SyncMode::Commit (embedded) or sync_mode: commit (server) to avoid future reorder-related corruption. See the storage section.

Authentication token expired or 401 errors

Login tokens expire after token_expiry_seconds (default: 3600 = 1 hour). If you receive repeated 401 Unauthorized responses:

  1. Re-login to obtain a fresh token.
  2. For long-running automation, schedule a periodic re-login before the token expires.
  3. When using a cluster, prefer cluster_user_login — it creates the same session token on every node so you can talk to any node without separate logins.

Cluster leader not elected / nodes cannot find each other

If the cluster is stuck without a leader:

  1. Verify the cluster array is identical in every node's config, including order.
  2. Verify each node's address appears exactly once in that array.
  3. Verify cluster_token is the same on all nodes.
  4. If using TLS, make sure the certificate's SANs (Subject Alternative Names) cover the hostnames used in cluster and address.
  5. Check that the cluster_term_timeout_ms is not too short for your network latency — increase it on high-latency links.
  6. Use /api/v1/cluster/status on each node to see which peers it considers reachable and who it thinks the leader is.

Query returns unexpected results

  1. Using verbose comparison without import — conditions like .value(LessThan(40.into())) compile but always match everything. Prefer the shorthand .key("age").less_than(40) which avoids this class of error entirely. If you must use the enum form, fully qualify it: .value(Comparison::LessThan(40.into())).
  2. Wrong exec variant — db.exec() (or db_exec on the client) only accepts immutable queries (select, search). Passing a mutable query returns a 400 error on the server or a compile error in embedded Rust.
  3. Forgetting .query() — every builder chain must end with .query() (and .into() for batch execution on the server). A missing .query() is a compile-time error in Rust but easy to miss in dynamic-language clients.
  4. Index not created — search().index("key").value(v) requires the index to exist. If no index is present the query returns an error, not an empty result. Create it first with insert().index("key").

Server refuses to start with "address not found in cluster"

The local address field must match one of the entries in the cluster array exactly (including scheme and port). For example, http://localhost:3000 does not match http://127.0.0.1:3000.