nexu-io/open-design · error · Error

dynamic client registration failed: HTTP ${res.status} ${res

Error message

dynamic client registration failed: HTTP ${res.status} ${res.statusText} ${txt}

What it means

registerClient POSTs a Dynamic Client Registration (DCR) request to the auth server's registration_endpoint. Any non-2xx response is surfaced as a failure along with status, statusText, and up to 500 chars of body. Causes range from the endpoint rejecting DCR (4xx) to network or server errors (5xx).

Source

Thrown at apps/daemon/src/mcp-oauth.ts:269

  const body = {
    redirect_uris: [redirectUri],
    token_endpoint_auth_method: 'none',
    grant_types: ['authorization_code', 'refresh_token'],
    response_types: ['code'],
    client_name: 'Open Design',
    application_type: 'web',
  };
  const res = await fetchImpl(registrationEndpoint, {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      accept: 'application/json',
    },
    body: JSON.stringify(body),
  });
  if (!res.ok) {
    const txt = await safeText(res);
    throw new Error(
      `dynamic client registration failed: HTTP ${res.status} ${res.statusText} ${txt}`,
    );
  }
  const json = (await res.json()) as { client_id?: string; client_secret?: string };
  if (!json.client_id) {
    throw new Error('dynamic client registration response missing client_id');
  }
  const out: { clientId: string; clientSecret?: string } = { clientId: json.client_id };
  if (json.client_secret) out.clientSecret = json.client_secret;
  return out;
}

/**
 * Cached version of `registerClient`. Looks up `(authServerIssuer, redirectUri)`
 * in the cache file and re-uses the existing client; falls back to a fresh
 * DCR call when nothing is cached.
 */
export async function getOrRegisterClient(

View on GitHub (pinned to 5be4028344)

Solutions

  1. Inspect the embedded status and body text in the message to see the server's reason.
  2. Confirm registration_endpoint is correct and reachable.
  3. Verify redirectUri is permitted by the provider.
  4. If DCR is unsupported, pre-register a client and seed the cache (see getOrRegisterClient).
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await registerClient(registrationEndpoint, redirectUri);
} catch (e) {
  if (/dynamic client registration failed/i.test(e.message)) {
    // message carries HTTP status + up to 500 chars of body
    logOAuthDetail(e.message);
    // for providers that reject DCR, fall back to a pre-registered client
  }
  throw e;
}

Prevention

When it happens

Trigger: Auth server rejected DCR with 400, 401, or 403; registration_endpoint is wrong or unreachable; server returned 5xx; rate limited with 429.

Common situations: An MCP provider does not actually support DCR despite advertising an endpoint; a corporate proxy returns 4xx; the redirectUri is not allowlisted.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/0cf6e062075c89a5. Report an issue: GitHub.