gravitational/teleport · error

prompt returned invalid credential: %#v

Error message

prompt returned invalid credential: %#v

What it means

The web prompt implementation (prompt.go) presents credential choices to the user, collects a free-form choice string (wchoice), and maps it back to a *CredentialInfo via a credMap. If the returned string does not correspond to any presented credential, PromptCredential fails with this error rather than returning an unknown credential. It protects the assertion-selection step from bogus prompt output.

Source

Thrown at lib/auth/webauthncli/prompt.go:175

		cred := &CredentialInfo{
			ID: []byte(c.CredentialID),
			User: UserInfo{
				UserHandle: c.User.UserHandle,
				Name:       c.User.Name,
			},
		}
		credMap[cred] = c
		wcreds[i] = cred
	}

	wchoice, err := p.impl.PromptCredential(wcreds)
	if err != nil {
		return nil, trace.Wrap(err)
	}

	choice, ok := credMap[wchoice]
	if !ok {
		return nil, fmt.Errorf("prompt returned invalid credential: %#v", wchoice)
	}
	return choice, nil
}

View on GitHub (pinned to 1283425b60)

Solutions

  1. Ensure the prompt's returned string is exactly the key used in credMap (same encoding/case as the presented credential identifiers).
  2. Regenerate the prompt UI from the same creds slice used to build credMap so the ID sets match.
  3. If a user submits an unknown/stale ID, re-prompt with the current credential list instead of passing it through.
  4. Log wchoice and the available keys to spot encoding/format mismatches.

Example fix

// before (front-end returns user-typed raw ID, map is keyed by base64)
wchoice := userInput.rawCredentialID
choice, err := prompt.PromptCredential(creds)
// after
wchoice := base64.RawURLEncoding.EncodeToString(userInput.rawCredentialIDBytes)
choice, err := prompt.PromptCredential(creds)
Defensive patterns

Strategy: validation

Validate before calling

wchoice, err := readUserChoice()
if err != nil { return err }
if _, ok := credMap[wchoice]; !ok {
    return fmt.Errorf("%q is not one of the offered credentials", wchoice)
}

Type guard

func isKnownCredentialChoice(credMap map[string]*CredentialInfo, wchoice string) bool {
    _, ok := credMap[wchoice]
    return ok
}

Try / catch

choice, err := wp.PromptCredential(creds)
if err != nil {
    if strings.Contains(err.Error(), "prompt returned invalid credential") {
        // re-show the prompt with the current credential list
        return wp.PromptCredential(creds)
    }
    return nil, trace.Wrap(err)
}

Prevention

When it happens

Trigger: A WebAuthn login with credential picker where the prompt handler returns a choice string that is not one of the offered credential IDs — e.g. the user/UI supplies an arbitrary or stale value, or the map was built from a different credential set than the prompt displayed.

Common situations: Custom web prompts echoing a different identifier format (e.g. raw ID vs base64-encoded ID); front-end code caching an old credential ID; race where the credential list changed between display and submission; test harnesses injecting arbitrary strings.

Related errors


AI-assisted analysis of gravitational/teleport@1283425b60 (2026-09-02). Data as JSON: /api/errors/ac37ceda33ab067d. Report an issue: GitHub.