{"record":{"id":"33875673b18c223a","repo":"ory/kratos","slug":"no-oidc-provider-was-set","errorCode":null,"errorMessage":"no oidc provider was set","messagePattern":"no oidc provider was set","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"selfservice/strategy/oidc/strategy_settings.go","lineNumber":634,"sourceCode":"\n\tif ctxUpdate.Flow != nil {\n\t\tctxUpdate.Flow.UI.ResetMessages()\n\t\tctxUpdate.Flow.UI.SetCSRF(s.d.GenerateCSRFToken(r))\n\t}\n\n\treturn err\n}\n\nfunc (s *Strategy) Link(ctx context.Context, i *identity.Identity, credentialsConfig sqlxx.JSONRawMessage) (err error) {\n\tctx, span := s.d.Tracer(ctx).Tracer().Start(ctx, \"selfservice.strategy.oidc.Strategy.Link\")\n\tdefer otelx.End(span, &err)\n\n\tvar credentialsOIDCConfig identity.CredentialsOIDC\n\tif err := json.Unmarshal(credentialsConfig, &credentialsOIDCConfig); err != nil {\n\t\treturn err\n\t}\n\tif len(credentialsOIDCConfig.Providers) != 1 {\n\t\treturn errors.New(\"no oidc provider was set\")\n\t}\n\tcredentialsOIDCProvider := credentialsOIDCConfig.Providers[0]\n\n\tif err := s.linkCredentials(\n\t\tctx,\n\t\ti,\n\t\t// The tokens in this credential are coming from the existing identity. Hence, the values are already encrypted.\n\t\tcredentialsOIDCProvider.GetTokens(),\n\t\tcredentialsOIDCProvider.Provider,\n\t\tcredentialsOIDCProvider.Subject,\n\t\tcredentialsOIDCProvider.Organization,\n\t); err != nil {\n\t\treturn err\n\t}\n\n\tif err := s.d.IdentityManager().Update(ctx, i, identity.ManagerAllowWriteProtectedTraits); err != nil {\n\t\treturn err\n\t}","sourceCodeStart":616,"sourceCodeEnd":652,"githubUrl":"https://github.com/ory/kratos/blob/b86338da04a040247a07f46100a86dcfb3875909/selfservice/strategy/oidc/strategy_settings.go#L616-L652","documentation":"During the settings flow, Link unmarshals the identity's stored oidc credentials config and requires exactly one provider to link. If the credentials JSON holds zero or more than one OIDC providers, this error is returned because the linking operation cannot disambiguate which provider to use.","triggerScenarios":"Calling the settings-flow link endpoint for the oidc credentials type when the identity's credentials_config.providers array is empty or contains multiple entries.","commonSituations":"Identity was created without any linked OIDC provider; corrupt or manually edited credentials metadata; a legacy identity that accumulated several linked providers.","solutions":["Ensure the identity actually has exactly one linked OIDC provider before attempting to link more credentials","Inspect the identity via GET /admin/identities/{id} and check credentials.oidc.config.providers length","If multiple providers are linked, link via the specific provider by re-authenticating through the OIDC flow rather than the settings link endpoint"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"var cfg identity.CredentialsOIDC; json.Unmarshal(creds.Config, &cfg); if len(cfg.Providers) != 1 { /* skip linking */ }","typeGuard":"func hasExactlyOneOIDCProvider(c identity.CredentialsOIDC) bool { return len(c.Providers) == 1 }","tryCatchPattern":"if err := s.linkCredentials(...); err != nil && strings.Contains(err.Error(), \"no oidc provider was set\") { // prompt user to link via OIDC login instead }","preventionTips":["Check the identity's linked providers before calling link","Avoid hand-editing credentials_config JSON","Migrate multi-provider identities via the OIDC login flow"],"tags":["go","oidc","identity","settings-flow"],"backgroundTag":"empty-required-field","analyzedSha":"b86338da04a040247a07f46100a86dcfb3875909","analyzedAt":"2026-09-07T15:58:15.934Z","contentChangedAt":"2026-09-07T15:58:15.934Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}