dotnet/aspnetcore · error
Unknown passkey operation '${this.attrs.operation}'.
Error message
Unknown passkey operation '${this.attrs.operation}'. What it means
Thrown by obtainCredential when this.attrs.operation is neither 'Create' nor 'Request'. The operation is read once in connectedCallback from the element's 'operation' attribute (PasskeySubmit.razor.js:46); a missing, misspelled, or differently-cased value falls through to the else branch.
Source
Thrown at src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/Account/Shared/PasskeySubmit.razor.js:77
}
disconnectedCallback() {
this.abortController?.abort();
}
async obtainCredential(useConditionalMediation, signal) {
if (!browserSupportsPasskeys) {
throw new Error('Some passkey features are missing. Please update your browser.');
}
if (this.attrs.operation === 'Create') {
return await createCredential(signal);
} else if (this.attrs.operation === 'Request') {
const email = new FormData(this.internals.form).get(this.attrs.emailName);
const mediation = useConditionalMediation ? 'conditional' : undefined;
return await requestCredential(email, mediation, signal);
} else {
throw new Error(`Unknown passkey operation '${this.attrs.operation}'.`);
}
}
async obtainAndSubmitCredential(useConditionalMediation = false) {
this.abortController?.abort();
this.abortController = new AbortController();
const signal = this.abortController.signal;
const formData = new FormData();
try {
const credential = await this.obtainCredential(useConditionalMediation, signal);
const credentialJson = JSON.stringify(credential);
formData.append(`${this.attrs.name}.CredentialJson`, credentialJson);
} catch (error) {
if (error.name === 'AbortError') {
// The user explicitly canceled the operation - return without error.
return;
}
console.error(error);View on GitHub (pinned to 294cab2f9b)
Solutions
- Set operation="Create" or operation="Request" exactly (case-sensitive) on every <passkey-submit> usage.
- If the attribute may change dynamically, re-read it in obtainCredential rather than caching in connectedCallback.
- Add a server-side/component assertion that the operation attribute is one of the two allowed values.
- Default to a known operation when the attribute is absent if that fits your UX.
Example fix
// before <passkey-submit name="..." /> <!-- missing operation --> // after <passkey-submit operation="Create" name="..." />
Defensive patterns
Strategy: validation
Validate before calling
const VALID_OPS = new Set(['Create','Request']);
function validOperation(op) { return VALID_OPS.has(op); } Type guard
type PasskeyOp = 'Create' | 'Request';
function isPasskeyOp(v: any): v is PasskeyOp { return v === 'Create' || v === 'Request'; } Try / catch
null
Prevention
- Always set operation with the exact casing on <passkey-submit>.
- Assert the attribute at render/build time.
- Re-read the attribute if it can change dynamically.
When it happens
Trigger: Rendering <passkey-submit> without an operation attribute; using operation="create" (lowercase) or operation="login"/"register"; a typo like operation="Reqest"; dynamically setting the attribute after connectedCallback (it is only read on connect).
Common situations: Template authoring mistake; casing mismatch (the code is case-sensitive); changing the attribute post-mount without re-reading; copy of the component that drops the attribute.
Related errors
- EqualTo validator requires a non-empty "other" parameter.
- FileExtensions validator requires a non-empty "extensions" p
- Range validator requires at least one of "min" or "max" para
- regex validator requires a non-empty "pattern" parameter.
- length/minlength/maxlength validator requires at least one o
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/10423f02b4be9450.
Report an issue: GitHub.