{"record":{"id":"33b82fcdc5aae3ae","repo":"Tencent/WeKnora","slug":"dynamic-client-registration-failed-w","errorCode":null,"errorMessage":"dynamic client registration failed: %w","messagePattern":"dynamic client registration failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/mcp/oauth_manager.go","lineNumber":106,"sourceCode":") (authorizationURL, attemptID string, err error) {\n\tif !service.AuthConfig.IsOAuth() {\n\t\treturn \"\", \"\", fmt.Errorf(\"MCP service %s does not use OAuth\", service.ID)\n\t}\n\tprincipal = principal.Normalize()\n\tif !principal.Valid() {\n\t\treturn \"\", \"\", fmt.Errorf(\"principal context is required to authorize OAuth MCP service %s\", service.ID)\n\t}\n\n\th, err := m.newHandler(ctx, service, tenantID, principal, redirectURI)\n\tif err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\n\t// Register a client dynamically if we don't have one yet for this service.\n\texisting, _ := m.repo.GetClient(ctx, tenantID, service.ID)\n\tif existing == nil {\n\t\tif err := h.RegisterClient(ctx, clientRegistrationName); err != nil {\n\t\t\treturn \"\", \"\", fmt.Errorf(\"dynamic client registration failed: %w\", err)\n\t\t}\n\t\tclientID := h.GetClientID()\n\t\tif clientID == \"\" {\n\t\t\treturn \"\", \"\", fmt.Errorf(\"dynamic client registration returned an empty client_id\")\n\t\t}\n\t\tif err := m.repo.SaveClient(ctx, &types.MCPOAuthClient{\n\t\t\tTenantID:    tenantID,\n\t\t\tServiceID:   service.ID,\n\t\t\tClientID:    clientID,\n\t\t\tRedirectURI: redirectURI,\n\t\t}); err != nil {\n\t\t\tlogger.GetLogger(ctx).Warnf(\"failed to persist MCP oauth client: %v\", err)\n\t\t}\n\t}\n\n\tverifier, err := transport.GenerateCodeVerifier()\n\tif err != nil {\n\t\treturn \"\", \"\", fmt.Errorf(\"failed to generate PKCE verifier: %w\", err)","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/mcp/oauth_manager.go#L88-L124","documentation":"Wraps a failure from the OAuth handler's dynamic client registration (RFC 7591) performed when no client is stored for the service. StartAuthorization registers a new client with the provider; if the provider rejects or the registration HTTP call fails, the error is wrapped and the authorization flow aborts before producing an authorize URL.","triggerScenarios":"First OAuth start for a service (no stored MCPOAuthClient), h.RegisterClient hits the provider's registration endpoint and fails: 4xx from provider, discovery metadata missing registration_endpoint, network/SSRF-guard block, timeout.","commonSituations":"Provider does not support dynamic client registration (returns 400/401/404 on /register); registration_endpoint absent from the provider's metadata; outbound firewall/SSRF guard blocks the registration URL; provider requires pre-registered client credentials instead.","solutions":["Confirm the provider supports RFC 7591 dynamic registration and exposes registration_endpoint in its metadata","Register a client manually with the provider and seed m.repo.SaveClient so GetClient returns non-nil","Check the wrapped cause for HTTP status/timeouts; verify outbound network/SSRF policy allows the provider URL","Fix provider-side registration requirements (e.g. required client metadata fields, software statement)"],"exampleFix":"// before\nclientID := h.GetClientID()\nif clientID == \"\" {\n    return \"\", \"\", fmt.Errorf(\"dynamic client registration returned an empty client_id\")\n}\n// after: fall back to a statically configured client\nclientID := h.GetClientID()\nif clientID == \"\" {\n    if cfgClient := config.StaticOAuthClient(service.ID); cfgClient != \"\" {\n        clientID = cfgClient\n    } else {\n        return \"\", \"\", fmt.Errorf(\"dynamic client registration returned an empty client_id\")\n    }\n}","handlingStrategy":"fallback","validationCode":"// pre-flight: check provider metadata advertises dynamic registration\nmeta, err := fetchProviderMetadata(ctx, *svc.URL)\nif err != nil || meta.RegistrationEndpoint == \"\" {\n    return fmt.Errorf(\"provider does not support dynamic registration; configure a static client\")\n}","typeGuard":null,"tryCatchPattern":"_, _, err := mgr.StartAuthorizationForService(ctx, svc, tenantID, principal, redirect, \"\")\nif err != nil && strings.Contains(err.Error(), \"dynamic client registration failed\") {\n    // fall back to pre-registered client credentials from config\n    return startAuthorizationWithStaticClient(ctx, svc, config.StaticClientFor(svc.ID))\n}","preventionTips":["Confirm the IdP supports RFC 7591 before relying on dynamic registration","Seed MCPOAuthClient rows for providers known not to support it","Whitelist provider registration endpoints in outbound/SSRF policy","Log registration HTTP failures with provider response bodies for triage"],"tags":["oauth","http","client-registration","network"],"backgroundTag":"oauth-client-registration-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}