sipeed/picoclaw · error
token is required
Error message
token is required
What it means
Returned as HTTP 400 by POST /api/oauth/login when method is "token" and the token field is empty after trimming. This is the only required field for token login — provider and method were already validated. Whitespace-only tokens are rejected because the value is strings.TrimSpace'd before the check.
Source
Thrown at web/backend/api/oauth.go:211
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
method := strings.ToLower(strings.TrimSpace(req.Method))
if !isOAuthMethodSupported(provider, method) {
http.Error(
w,
fmt.Sprintf("unsupported login method %q for provider %q", method, provider),
http.StatusBadRequest,
)
return
}
switch method {
case oauthMethodToken:
token := strings.TrimSpace(req.Token)
if token == "" {
http.Error(w, "token is required", http.StatusBadRequest)
return
}
cred := &auth.AuthCredential{
AccessToken: token,
Provider: provider,
AuthMethod: oauthMethodToken,
}
if err := h.persistCredentialAndConfig(provider, oauthMethodToken, cred); err != nil {
http.Error(w, fmt.Sprintf("token login failed: %v", err), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]any{
"status": "ok",
"provider": provider,
"method": method,View on GitHub (pinned to 49183d7e8d)
Solutions
- Include a non-empty, non-whitespace "token" string in the JSON body: {"provider":"anthropic","method":"token","token":"sk-ant-..."}.
- Trim the token client-side before submitting (token.trim()) so whitespace-only values are caught in the UI.
- Check that the JSON key is exactly "token", not "api_key"/"access_token".
- Ensure JSON.stringify does not drop the field because the value is undefined — default it or fail the submit.
Example fix
// before
await fetch('/api/oauth/login', {method:'POST', body: JSON.stringify({provider, method:'token', token: apiKey || undefined})});
// undefined is omitted by JSON.stringify -> 400 token is required
// after
const token = (apiKey ?? '').trim();
if (!token) throw new Error('Paste an API token first');
await fetch('/api/oauth/login', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({provider, method:'token', token})}); Defensive patterns
Strategy: validation
Validate before calling
function assertToken(token) {
const t = String(token ?? '').trim();
if (!t) throw new Error('token is required');
return t;
} Type guard
function hasToken(v) { return typeof v === 'string' && v.trim().length > 0; } Prevention
- Trim the pasted token in the UI and disable submit when empty.
- JSON.stringify drops undefined fields — default the field or block submit so the key is always present.
- Use the exact JSON key 'token', not 'api_key' or 'access_token'.
When it happens
Trigger: POST /api/oauth/login with {"provider":"anthropic","method":"token","token":""} or {"token":" "} or with the field named differently (e.g. "api_key" or "accessToken") so the struct field stays zero.
Common situations: Frontend form with an empty paste field; token stored under a different key in state and serialized as token: undefined (dropped by JSON.stringify); users pasting a newline-only string; API clients built from the Anthropic docs that send an Authorization header instead of a body token.
Related errors
- unsupported provider %q
- unsupported login method %q for provider %q
- missing flow id
- no refresh token available
- no access token in response
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/c1a9bb47849bbcb8.
Report an issue: GitHub.