{"record":{"id":"3b5745174be088aa","repo":"Tencent/WeKnora","slug":"dynamic-client-registration-returned-an-empty-clie","errorCode":null,"errorMessage":"dynamic client registration returned an empty client_id","messagePattern":"dynamic client registration returned an empty client_id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/mcp/oauth_manager.go","lineNumber":110,"sourceCode":"\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)\n\t}\n\tchallenge := transport.GenerateCodeChallenge(verifier)\n\tstate, err := transport.GenerateState()\n\tif err != nil {","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/mcp/oauth_manager.go#L92-L128","documentation":"Raised when dynamic client registration completes without error but the handler returns an empty client_id, meaning the provider response lacked the required identifier. StartAuthorization treats this as a hard failure because the authorization URL cannot be built without a client_id.","triggerScenarios":"Provider's /register endpoint returns 2xx with a body missing client_id (or the handler fails to parse it), immediately after h.RegisterClient succeeds.","commonSituations":"Provider returns a non-standard registration response (e.g. only registration_client_uri); misbehaving mock/idp in dev; response shape changed after a provider upgrade; JSON field name mismatch in parsing.","solutions":["Inspect the provider's registration response for a non-standard body and fix parsing expectations","Upgrade/patch the transport.OAuthHandler registration parsing to match the provider's response format","Use a static, pre-registered client_id with the provider instead of dynamic registration","Log the raw registration response to confirm what the provider returned"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// sanity-check the registration path with a dry-run against the provider\nresp, err := http.Post(*svc.URL+\"/register\", \"application/json\", strings.NewReader(sampleReg))\nif err == nil {\n    var body map[string]any\n    json.NewDecoder(resp.Body).Decode(&body)\n    if _, ok := body[\"client_id\"]; !ok {\n        return fmt.Errorf(\"provider registration response lacks client_id; use static client\")\n    }\n}","typeGuard":"func hasClientID(reg map[string]any) bool {\n    id, ok := reg[\"client_id\"]\n    return ok && s, _ := id.(string); ok && s != \"\"\n}","tryCatchPattern":"_, _, err := mgr.StartAuthorizationForService(ctx, svc, tenantID, principal, redirect, \"\")\nif err != nil && strings.Contains(err.Error(), \"empty client_id\") {\n    log.Warn(\"provider returned non-standard registration response; using static client\")\n    return startAuthorizationWithStaticClient(ctx, svc, config.StaticClientFor(svc.ID))\n}\nif err != nil { return err }","preventionTips":["Verify the IdP's registration response includes client_id (RFC 7591 requirement)","Keep the OAuth handler library updated for provider response-shape changes","Capture the raw registration response in logs for debugging","Prefer static client registration for providers with non-standard responses"],"tags":["oauth","client-registration","protocol","parsing"],"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"}