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

  1. Generate the correct token: run `claude setup-token` and copy the value that starts with sk-ant-oat01-.
  2. If you meant to use an API key instead, use the paste-token path (LoginPasteToken), not LoginSetupToken.
  3. Re-copy the full token from the terminal, making sure the first characters are sk-ant-oat01- and nothing precedes them.
  4. 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

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


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/b22842e9cf927adb. Report an issue: GitHub.