{"record":{"id":"78ea7ea1da6f2459","repo":"sipeed/picoclaw","slug":"invalid-setup-token-too-short-expected-at-least","errorCode":null,"errorMessage":"invalid setup token: too short (expected at least 80 characters)","messagePattern":"invalid setup token: too short \\(expected at least 80 characters\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/auth/token.go","lineNumber":53,"sourceCode":"\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\":\n\t\treturn \"platform.openai.com\"\n\tdefault:\n\t\treturn provider\n\t}","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/auth/token.go#L35-L71","documentation":"The token passed the prefix check but is shorter than 80 characters, and real sk-ant-oat01- setup tokens are always at least 80 chars. This guard exists to catch truncated pastes before an opaque HTTP 401 from the API later. Only the total length is checked; no other structure is validated.","triggerScenarios":"Pasting only the first line/wrapped fragment of a token that was line-wrapped by a terminal; clipboard truncation; hand-typing a prefix plus partial body; shell variable storing a cut-off value.","commonSituations":"Terminal wraps long tokens across lines and the user copies just one line; tmux/screen copy-mode grabbing a partial region; secret managers clipping long values; pasting with a middle-click selection that stopped early.","solutions":["Re-copy the entire token from `claude setup-token` output as one single-line selection, then verify length: `[ ${#TOKEN} -ge 80 ]`.","Disable terminal line-wrapping interference by copying from a wider terminal or redirecting output to a file and copying from there.","If storing in env/secrets, confirm the stored value survived intact (compare lengths before and after storage).","Retry the login flow with the full token."],"exampleFix":"// before\n// user pasted \"sk-ant-oat01-abc123\" (23 chars) -> \"too short\" error\n\n// after - validate before calling, fail with actionable message\nif len(strings.TrimSpace(token)) < 80 {\n    return fmt.Errorf(\"token looks truncated (%d chars, need >= 80); re-copy the full token\", len(token))\n}\ncred, err := auth.LoginSetupToken(strings.NewReader(token))","handlingStrategy":"validation","validationCode":"func isCompleteSetupToken(s string) bool {\n    s = strings.TrimSpace(s)\n    return strings.HasPrefix(s, \"sk-ant-oat01-\") && len(s) >= 80\n}\n\nif !isCompleteSetupToken(token) {\n    return fmt.Errorf(\"token truncated (%d chars, need >= 80); re-copy\", len(token))\n}","typeGuard":"func isCompleteSetupToken(s string) bool {\n    s = strings.TrimSpace(s)\n    return strings.HasPrefix(s, \"sk-ant-oat01-\") && len(s) >= 80\n}","tryCatchPattern":"if _, err := auth.LoginSetupToken(r); err != nil {\n    if strings.Contains(err.Error(), \"too short\") {\n        return errors.New(\"token was cut off; widen the terminal, re-copy the single full line, and retry\")\n    }\n    return err\n}","preventionTips":["Copy setup tokens from unwrapped output (redirect to a file, copy from the file).","Verify length client-side: len(token) >= 80 before calling.","Prefer secret files/env over manual paste for automation."],"tags":["auth","go","anthropic","validation","token-length"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}