bytedance/deer-flow · error · HTTPException
Token error: {payload.value}
Error message
Token error: {payload.value} What it means
HTTP 401 raised when the access_token cookie exists but decode_token() returns a TokenError (malformed JWT, bad signature, expired, unknown algorithm, invalid claims). The specific TokenError value is mapped via token_error_to_code() into the AuthErrorResponse code and surfaced in the message as 'Token error: <value>'.
Source
Thrown at backend/app/gateway/deps.py:762
AUTH_SOURCE_SESSION,
AUTH_SOURCE_AUTH_DISABLED,
AUTH_SOURCE_INTERNAL,
}:
return state_user
from app.gateway.auth import decode_token
from app.gateway.auth.errors import AuthErrorCode, AuthErrorResponse, TokenError, token_error_to_code
access_token = request.cookies.get("access_token")
if not access_token:
raise HTTPException(
status_code=401,
detail=AuthErrorResponse(code=AuthErrorCode.NOT_AUTHENTICATED, message="Not authenticated").model_dump(),
)
payload = decode_token(access_token)
if isinstance(payload, TokenError):
raise HTTPException(
status_code=401,
detail=AuthErrorResponse(code=token_error_to_code(payload), message=f"Token error: {payload.value}").model_dump(),
)
provider = get_local_provider()
user = await provider.get_user(payload.sub)
if user is None:
raise HTTPException(
status_code=401,
detail=AuthErrorResponse(code=AuthErrorCode.USER_NOT_FOUND, message="User not found").model_dump(),
)
# Token version mismatch → password was changed, token is stale
if user.token_version != payload.ver:
raise HTTPException(
status_code=401,
detail=AuthErrorResponse(code=AuthErrorCode.TOKEN_INVALID, message="Token revoked (password changed)").model_dump(),
)View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Read the echoed TokenError value in the 401 detail — EXPIRED means just re-login; SIGNATURE/BAD_SIGNATURE means the secret rotated and all clients must re-login
- Log in again to mint a token under the current secret; clear the stale cookie first if the login flow does not overwrite it
- If signature errors affect everyone right after deploy, confirm the JWT secret is persisted (not randomly generated per-process) in your deployment config
- Fix clock skew (NTP) if tokens fail as expired immediately after issuance
Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
catch (e) {
if (e.status === 401 && e.detail?.message?.startsWith('Token error:')) {
clearSession(); goToLogin(); // any token-level failure is unrecoverable client-side
return;
}
throw e;
} Prevention
- Persist the JWT signing secret across restarts (volume/env), never regenerate per boot
- Keep server clocks NTP-synced to avoid premature token expiry
- Treat all TokenError variants the same: clear cookie, re-authenticate
When it happens
Trigger: Any authenticated call with a present-but-invalid JWT cookie: token signed with a rotated secret, token past its exp, tampered payload, or a token issued by a different issuer. The exact TokenError variant is echoed in the detail message.
Common situations: JWT secret (AUTH_SECRET or equivalent) rotated or regenerated after a restart, invalidating all outstanding cookies; clock skew between issuer and verifier causing premature expiry; stale cookie from an old deployment left in the browser; manually edited cookie.
Related errors
- Invalid token
- USER_NOT_FOUND
- TOKEN_INVALID
- Failed to read JWT secret from {secret_file}. Set AUTH_JWT_S
- Failed to persist JWT secret to {secret_file}. Set AUTH_JWT_
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/3ddb890a68421c41.
Report an issue: GitHub.