{"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/251596fc0de2f9528c00c224252fd073a99973f4/kernel/mcp/client/oauth.go#L396-L432","documentation":"Wrapped error at oauth.go:413-414 when putOAuthCredential fails to persist the final token credential after a successful authorization-code exchange. The tokens were obtained but cannot be stored, so the next request will not have valid credentials and the flow must be repeated.","triggerScenarios":"putOAuthCredential returns non-nil right after the token fields (AccessToken, RefreshToken, Expiry, Scopes, TokenType) are populated on the credential. Identical storage failure mode as error 327 but at the final-save step.","commonSituations":"Disk full; keystore file locked by another process; permissions revoked on the data directory; keystore corruption; AV locking the credential file on Windows.","solutions":["Check the wrapped error's filesystem errno and resolve space/permissions on the kernel data directory.","Ensure single-instance operation (no second SiYuan holding the workspace lock).","After resolving the storage issue, re-run authorization — the in-memory source was not installed (h.source set only after a successful save)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err = putOAuthCredential(credential); err != nil {\n    // Final token obtained but not persisted; user must re-authorize after storage is fixed.\n    logging.LogErrorf(\"mcp oauth: persist credentials failed: %s\", err)\n    return fmt.Errorf(\"save OAuth credentials: %w\", err)\n}","preventionTips":["Maintain writable, sufficiently sized kernel data directory.","Single-instance operation per workspace to prevent keystore lock contention.","Monitor filesystem health to catch credential-save failures early."],"tags":["oauth","mcp","storage","persistence","keystore","filesystem"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}