{"record":{"id":"b22842e9cf927adb","repo":"sipeed/picoclaw","slug":"invalid-setup-token-expected-prefix-sk-ant-oat01","errorCode":null,"errorMessage":"invalid setup token: expected prefix sk-ant-oat01-","messagePattern":"invalid setup token: expected prefix sk-ant-oat01-","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/auth/token.go","lineNumber":49,"sourceCode":"\t}, nil\n}\n\nfunc LoginSetupToken(r io.Reader) (*AuthCredential, error) {\n\tfmt.Println(\"Paste your setup token from `claude setup-token`:\")\n\tfmt.Print(\"> \")\n\n\tscanner := bufio.NewScanner(r)\n\tif !scanner.Scan() {\n\t\tif err := scanner.Err(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"reading token: %w\", err)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"no input received\")\n\t}\n\n\ttoken := strings.TrimSpace(scanner.Text())\n\n\tif !strings.HasPrefix(token, \"sk-ant-oat01-\") {\n\t\treturn nil, fmt.Errorf(\"invalid setup token: expected prefix sk-ant-oat01-\")\n\t}\n\n\tif len(token) < 80 {\n\t\treturn nil, fmt.Errorf(\"invalid setup token: too short (expected at least 80 characters)\")\n\t}\n\n\treturn &AuthCredential{\n\t\tAccessToken: token,\n\t\tProvider:    \"anthropic\",\n\t\tAuthMethod:  \"oauth\",\n\t}, nil\n}\n\nfunc providerDisplayName(provider string) string {\n\tswitch provider {\n\tcase \"anthropic\":\n\t\treturn \"console.anthropic.com\"\n\tcase \"openai\":","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/auth/token.go#L31-L67","documentation":"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.","triggerScenarios":"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).","commonSituations":"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).","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."],"exampleFix":"// before - wrong token type\ncred, err := auth.LoginSetupToken(strings.NewReader(\"sk-ant-api03-xxxx...\"))\n\n// after - generate with `claude setup-token`, or route API keys to the right flow\nif strings.HasPrefix(token, \"sk-ant-api\") {\n    cred, err = auth.LoginPasteToken(\"anthropic\", strings.NewReader(token))\n} else {\n    cred, err = auth.LoginSetupToken(strings.NewReader(token))\n}","handlingStrategy":"validation","validationCode":"const setupTokenPrefix = \"sk-ant-oat01-\"\n\nfunc isSetupToken(s string) bool {\n    return strings.HasPrefix(strings.TrimSpace(s), setupTokenPrefix)\n}\n\nif !isSetupToken(token) { return errors.New(\"not a setup token; run `claude setup-token`\") }","typeGuard":"func isSetupToken(s string) bool {\n    return strings.HasPrefix(strings.TrimSpace(s), \"sk-ant-oat01-\")\n}","tryCatchPattern":"if _, err := auth.LoginSetupToken(r); err != nil {\n    if strings.Contains(err.Error(), \"expected prefix sk-ant-oat01-\") {\n        // wrong token type: route API keys to LoginPasteToken instead\n        return auth.LoginPasteToken(\"anthropic\", r)\n    }\n    return err\n}","preventionTips":["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."],"tags":["auth","go","anthropic","validation","token-prefix"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}