dotnet/aspnetcore · error · Error

The server responded with status

Error message

The server responded with status ${response.status}.

What it means

Thrown by fetchWithErrorHandling after a non-ok HTTP response from the passkey endpoints (/Account/PasskeyCreationOptions, /Account/PasskeyRequestOptions). The server returned an HTTP error status (4xx/5xx), so the passkey credential flow cannot proceed. The response body is logged to console.error before throwing.

Solutions

  1. Open DevTools Network tab, inspect the failing /Account/Passkey* request status and response body (already console.error'd) to identify the exact HTTP code.
  2. If 400 Bad Request: verify the anti-forgery token is being sent (the form must include the request verification token and cookies:'include' must remain in effect).
  3. If 401/403: confirm the user is still authenticated and the endpoint's [Authorize] policy is satisfied before invoking passkey UI.
  4. If 404: confirm AddPasskey / MapPasskeyEndpoints is registered in Program.cs and the route matches '/Account/PasskeyCreationOptions'.
  5. If 500: inspect the server-side exception in ASP.NET Core logs; the passkey options handler likely threw.

Example fix

// before
const response = await fetch(url, { credentials: 'include', ...options });
if (!response.ok) { /* generic throw */ }

// after — surface server-provided error text to the UI
async function fetchWithErrorHandling(url, options = {}) {
  const response = await fetch(url, { credentials: 'include', ...options });
  if (!response.ok) {
    const text = await response.text().catch(() => '');
    throw new Error(`Passkey request to ${url} failed (${response.status}): ${text}`);
  }
  return response;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight the endpoint is reachable & authed before offering passkey UI
async function canReachPasskeyEndpoint() {
  try {
    const r = await fetch('/Account/PasskeyCreationOptions', {
      method: 'HEAD', credentials: 'include'
    });
    return r.ok || r.status === 405; // 405 = endpoint exists, HEAD not allowed
  } catch { return false; }
}

Try / catch

try {
  await component.obtainAndSubmitCredential();
} catch (e) {
  if (/server responded with status (\d+)/.test(e.message)) {
    const status = RegExp.$1;
    showUserError(status === 401 ? 'Session expired — please sign in again.' : 'Passkey request failed. Try a different sign-in method.');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling fetchWithErrorHandling against /Account/PasskeyCreationOptions or /Account/PasskeyRequestOptions when the ASP.NET Core account endpoint returns non-2xx. Anti-forgery token failure (400), missing authentication (401), server exception (500), or endpoint not mapped (404) all hit this path.

Common situations: Anti-forgery cookie/token not sent because credentials:'include' is overridden by a same-origin policy change; the Blazor account endpoints were customized or removed; the user session expired mid-flow; ASP.NET Core rate limiting or authorization policies reject the request.

Related errors


AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11). Data as JSON: /api/errors/d7b71564ad2bb13a. Report an issue: GitHub.

Appendix: source

Thrown at src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/Account/Shared/PasskeySubmit.razor.js:15

const browserSupportsPasskeys =
    typeof navigator.credentials !== 'undefined' &&
    typeof window.PublicKeyCredential !== 'undefined' &&
    typeof window.PublicKeyCredential.parseCreationOptionsFromJSON === 'function' &&
    typeof window.PublicKeyCredential.parseRequestOptionsFromJSON === 'function';

async function fetchWithErrorHandling(url, options = {}) {
    const response = await fetch(url, {
        credentials: 'include',
        ...options
    });
    if (!response.ok) {
        const text = await response.text();
        console.error(text);
        throw new Error(`The server responded with status ${response.status}.`);
    }
    return response;
}

async function createCredential(signal) {
    const optionsResponse = await fetchWithErrorHandling('/Account/PasskeyCreationOptions', {
        method: 'POST',
        signal,
    });
    const optionsJson = await optionsResponse.json();
    const options = PublicKeyCredential.parseCreationOptionsFromJSON(optionsJson);
    return await navigator.credentials.create({ publicKey: options, signal });
}

async function requestCredential(email, mediation, signal) {
    const optionsResponse = await fetchWithErrorHandling(`/Account/PasskeyRequestOptions?username=${email}`, {
        method: 'POST',
        signal,

View on GitHub (pinned to 3600ca084e)