How to Troubleshoot Common Authentication Token Issues in AI‑Trader: 7 Diagnostic Methods

Most AI‑Trader authentication failures stem from malformed Authorization headers, expired user sessions, or stale agent tokens after rotation, all of which can be diagnosed by inspecting the header format and the agents or user_tokens database tables.

AI‑Trader (HKUDS/AI-Trader) implements a dual-token architecture that isolates trading-bot credentials from human user sessions. Understanding how to troubleshoot common authentication token issues in AI‑Trader requires familiarity with both the agent token system (for automated trading bots) and the user session token system (for UI and API clients), each managed in service/server/services.py and extracted via service/server/utils.py.

1. Verify the Authorization Header Format

Missing or malformed headers generate immediate 401 – Invalid token errors because utils._extract_token expects a specific Bearer format.

In service/server/utils.py (lines 27–33), the extraction logic strips the Bearer prefix only if present:

def _extract_token(authorization: str = None) -> Optional[str]:
    if not authorization:
        return None
    if authorization.startswith("Bearer "):
        return authorization[7:]
    return authorization

Symptoms: Every authenticated endpoint returns detail: 'Invalid token'.

Diagnostic check:

curl -v http://localhost:8000/api/users/me   # No Authorization header

Fix: Ensure the client sends Authorization: Bearer <token>. While utils._extract_token falls back to returning the raw string if the prefix is missing, relying on this creates inconsistency with external API clients that enforce the Bearer scheme.

2. Handle Stale Agent Tokens After Rotation

Agent tokens are generated using secrets.token_urlsafe(32) inside services._issue_agent_token (lines 54–62 in service/server/services.py). When rotation occurs, the old value in the agents table is overwritten, invalidating previous requests.

Symptoms: 401 – Invalid token immediately after calling a rotation endpoint.

Diagnostic check:

SELECT id, name, token FROM agents WHERE id = <agent_id>;

Fix: Update the client configuration with the new token returned by the rotation response. The server stores the new credential in the token column and clears token_expires_at on rotation.

3. Diagnose Expired User Session Tokens

User sessions default to a 7‑day TTL defined in services._create_user_session (lines 82–90). Tokens are validated via services._get_user_by_token (lines 65–73), which queries the user_tokens table.

Symptoms: Authentication works intermittently or fails after a week.

Diagnostic check:

SELECT token, expires_at FROM user_tokens WHERE token = '<token>';

Fix: If expires_at is less than the current UTC timestamp, re-authenticate via /api/users/login to obtain a fresh token. Alternatively, modify the timedelta(days=7) value in services._create_user_session to extend the TTL.

4. Prevent Accidental Token Deletion During Cleanup

The periodic task utils.cleanup_expired_tokens (lines 93–105 in service/server/utils.py) deletes rows from user_tokens where expires_at exceeds the current time.

def cleanup_expired_tokens():
    now = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
    cursor.execute("DELETE FROM user_tokens WHERE expires_at < ?", (now,))

Symptoms: Tokens vanish from the database unexpectedly, causing sporadic 401 errors.

Fix: Ensure expires_at is stored in UTC ISO‑8601 format (e.g., 2024-01-15T10:00:00Z). If using custom TTL values, verify they exceed the intended session duration to prevent the cleanup routine from removing active sessions.

5. Fix Wallet‑Based Agent Token Recovery Failures

The recovery flow at /api/agents/token-recovery relies on utils.validate_address (lines 12–24 in service/server/utils.py), which normalizes Ethereum addresses and returns an empty string on validation failure.

Symptoms: 400 – Agent has no wallet‑based recovery configured.

Diagnostic check: Verify the agent’s wallet_address column contains a valid 40‑character hexadecimal address (e.g., 0x1234...abcd) stripped of 0x and lowercased by the validation logic.

Fix: Update the wallet_address field in the agents table to a valid Ethereum address before attempting recovery.

6. Standardize Bearer Prefix Handling

Both routes_agent.py and routes_users.py (e.g., lines 84–86) invoke utils._extract_token. While the function tolerates raw tokens, mixing prefixed and unprefixed headers across clients creates debugging complexity.

Symptoms: Authentication succeeds in some clients but fails in others (like Postman or cURL) despite using the same token value.

Fix: Enforce Authorization: Bearer <token> uniformly across all clients. Consider modifying utils._extract_token to reject unprefixed values if strict compliance is required.

7. Resolve Database Lock Errors During Token Issuance

SQLite’s write locks can trigger sqlite3.OperationalError: database is locked during concurrent token creation. While services._add_agent_points implements retry logic, token issuance functions do not currently retry.

Symptoms: Intermittent failures when calling login or rotation endpoints under load.

Diagnostic check: Monitor the application logs for lock errors coinciding with high write volume.

Fix: Reduce concurrent write contention or migrate to PostgreSQL using scripts/migrate_sqlite_to_postgres.py to eliminate SQLite’s locking limitations.

Summary

  • AI‑Trader uses two distinct tokens: Agent tokens (in the agents table) and user session tokens (in the user_tokens table with a 7‑day default expiration).
  • Always verify the Authorization header includes the Bearer prefix before sending to utils._extract_token.
  • Rotate agent tokens atomically: Update client configurations immediately after calling services._issue_agent_token.
  • Monitor expiration: Query expires_at in user_tokens and ensure utils.cleanup_expired_tokens uses UTC ISO‑8601 timestamps.
  • Validate wallet addresses before attempting token recovery via utils.validate_address.

Frequently Asked Questions

Why does my agent token suddenly return 401 after a restart?

The token was likely rotated or the agents table was updated without persisting the new credential to your client configuration. Query the token column directly in the database to confirm the stored value matches your request header.

How long do user session tokens remain valid?

By default, 7 days. This TTL is hardcoded as timedelta(days=7) inside services._create_user_session (lines 82–90). Once expired, the token is removed by utils.cleanup_expired_tokens, forcing re-authentication.

Can I use the same token extraction logic for external API clients?

Yes. The utils._extract_token function in service/server/utils.py handles both Bearer <token> and raw token formats. However, for consistency with standard OAuth2 clients, always transmit Authorization: Bearer <token>.

What causes "database is locked" errors during login?

SQLite’s file-level locking conflicts with concurrent writes. Token issuance lacks the retry logic found in other service methods. Switch to PostgreSQL via the provided migration script or serialize authentication requests to avoid write contention.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →