sipeed/picoclaw · error
invalid setup token: expected prefix sk-ant-oat01-
Error message
invalid setup token: expected prefix sk-ant-oat01-
What it means
The pasted token does not start with the literal prefix `sk-ant-oat01-`, which is the marker for Anthropic OAuth setup tokens (issued by `claude setup-token`). LoginSetupToken performs this strict prefix check before doing anything else with the token, so any other token shape (API key sk-ant-api..., session token, typo'd paste) is rejected immediately.
Source
Thrown at pkg/auth/token.go:49
}, nil
}
func LoginSetupToken(r io.Reader) (*AuthCredential, error) {
fmt.Println("Paste your setup token from `claude setup-token`:")
fmt.Print("> ")
scanner := bufio.NewScanner(r)
if !scanner.Scan() {
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("reading token: %w", err)
}
return nil, fmt.Errorf("no input received")
}
token := strings.TrimSpace(scanner.Text())
if !strings.HasPrefix(token, "sk-ant-oat01-") {
return nil, fmt.Errorf("invalid setup token: expected prefix sk-ant-oat01-")
}
if len(token) < 80 {
return nil, fmt.Errorf("invalid setup token: too short (expected at least 80 characters)")
}
return &AuthCredential{
AccessToken: token,
Provider: "anthropic",
AuthMethod: "oauth",
}, nil
}
func providerDisplayName(provider string) string {
switch provider {
case "anthropic":
return "console.anthropic.com"
case "openai":View on GitHub (pinned to 49183d7e8d)
Solutions
- Generate the correct token: run `claude setup-token` and copy the value that starts with sk-ant-oat01-.
- If you meant to use an API key instead, use the paste-token path (LoginPasteToken), not LoginSetupToken.
- Re-copy the full token from the terminal, making sure the first characters are sk-ant-oat01- and nothing precedes them.
- Check for clipboard managers mangling the paste; paste into a text editor first and inspect the first line.
Example fix
// before - wrong token type
cred, err := auth.LoginSetupToken(strings.NewReader("sk-ant-api03-xxxx..."))
// after - generate with `claude setup-token`, or route API keys to the right flow
if strings.HasPrefix(token, "sk-ant-api") {
cred, err = auth.LoginPasteToken("anthropic", strings.NewReader(token))
} else {
cred, err = auth.LoginSetupToken(strings.NewReader(token))
} Defensive patterns
Strategy: validation
Validate before calling
const setupTokenPrefix = "sk-ant-oat01-"
func isSetupToken(s string) bool {
return strings.HasPrefix(strings.TrimSpace(s), setupTokenPrefix)
}
if !isSetupToken(token) { return errors.New("not a setup token; run `claude setup-token`") } Type guard
func isSetupToken(s string) bool {
return strings.HasPrefix(strings.TrimSpace(s), "sk-ant-oat01-")
} Try / catch
if _, err := auth.LoginSetupToken(r); err != nil {
if strings.Contains(err.Error(), "expected prefix sk-ant-oat01-") {
// wrong token type: route API keys to LoginPasteToken instead
return auth.LoginPasteToken("anthropic", r)
}
return err
} Prevention
- Label stored secrets clearly: setup-token vs api-key.
- Check the prefix client-side before invoking the login flow.
- Route sk-ant-api* tokens to the API-key flow, never the setup-token flow.
When it happens
Trigger: Pasting an Anthropic API key (sk-ant-api03-...) instead of a setup token; pasting a Claude Pro/Max session token or OAuth code; a clipboard that grabbed the wrong string; extra invisible leading characters (rare — input is TrimSpace'd first).
Common situations: User confuses `claude setup-token` output with the API key from console.anthropic.com; user pastes only part of the token starting mid-string; provider mismatch (this login path is Anthropic-only).
Related errors
- invalid setup token: too short (expected at least 80 charact
- no models available
- failed to get WeCom QR code: response missing scode or auth_
- WeCom QR scan succeeded but bot credentials are missing
- invalid WeCom QR generate URL: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/b22842e9cf927adb.
Report an issue: GitHub.