{"record":{"id":"fbead83d8d9bc82c","repo":"siyuan-note/siyuan","slug":"save-oauth-credentials-w","errorCode":null,"errorMessage":"save OAuth credentials: %w","messagePattern":"save OAuth credentials: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/client/oauth.go","lineNumber":414,"sourceCode":"\ttoken, err := config.Exchange(exchangeCtx, callback.Code,\n\t\toauth2.VerifierOption(verifier),\n\t\toauth2.SetAuthURLParam(\"resource\", prm.Resource))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"exchange OAuth authorization code: %w\", err)\n\t}\n\tif token.TokenType != \"\" && !strings.EqualFold(token.TokenType, \"Bearer\") {\n\t\treturn fmt.Errorf(\"OAuth token endpoint returned unsupported token type %q\", token.TokenType)\n\t}\n\tcredential = registrationCredential\n\tcredential.TokenAuthMethod = authMethod\n\tcredential.AccessToken = token.AccessToken\n\tcredential.RefreshToken = token.RefreshToken\n\tcredential.TokenType = token.TokenType\n\tcredential.Expiry = token.Expiry\n\tcredential.Scopes = scopes\n\tcredential.Rejected = false\n\tif err = putOAuthCredential(credential); err != nil {\n\t\treturn fmt.Errorf(\"save OAuth credentials: %w\", err)\n\t}\n\th.sourceMu.Lock()\n\th.source = &storedOAuthTokenSource{credential: credential, client: h.client}\n\th.sourceMu.Unlock()\n\tsetMCPRuntimeStateForContext(ctx, h.server.ID, \"oauth_retrying\", 0, \"\", \"\")\n\treturn nil\n}\n\nfunc hasBearerChallenge(challenges []oauthex.Challenge) bool {\n\tfor _, challenge := range challenges {\n\t\tif strings.EqualFold(challenge.Scheme, \"bearer\") {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc bearerChallengeParam(challenges []oauthex.Challenge, name string) string {","sourceCodeStart":396,"sourceCodeEnd":432,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/mcp/client/oauth.go#L396-L432","documentation":"After a successful token exchange, the completed credential (access/refresh token, expiry, scopes) must be persisted with putOAuthCredential before the token source is installed. This error wraps a storage failure from that save; authorization succeeded but the credentials could not be stored, so the flow reports failure.","triggerScenarios":"Authorize() obtained a valid Bearer token and built the final credential, then putOAuthCredential(credential) returned an error while writing it to the credential store.","commonSituations":"Disk full or read-only workspace; permission changes on the data directory; storage corruption; concurrent write conflicts on the credential store.","solutions":["Inspect the wrapped underlying error to identify the storage failure","Ensure the SiYuan workspace/data directory is writable and has free disk space","Restart the kernel to release any transient store issues and retry the OAuth flow","Restore/repair the credential storage if it is corrupted"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Ensure storage is healthy before running the flow\nif err := checkWorkspaceWritable(); err != nil { return err }","typeGuard":null,"tryCatchPattern":"if err := h.Authorize(ctx, true); err != nil {\n    if strings.Contains(err.Error(), \"save OAuth credentials\") {\n        // fix disk/permission problem, then re-run authorization\n    }\n}","preventionTips":["Monitor free disk space and directory permissions on the workspace","Avoid killing the kernel mid-write; use graceful shutdown","Back up the credential store before kernel upgrades"],"tags":["oauth","mcp","persistence","storage"],"backgroundTag":"file-write-failed","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}