siyuan-note/siyuan · error
save OAuth credentials
Error message
save OAuth credentials: %w
What it means
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.
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
Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure storage is healthy before running the flow
if err := checkWorkspaceWritable(); err != nil { return err } Try / catch
if err := h.Authorize(ctx, true); err != nil {
if strings.Contains(err.Error(), "save OAuth credentials") {
// fix disk/permission problem, then re-run authorization
}
} Prevention
- 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
When it happens
Trigger: Authorize() obtained a valid Bearer token and built the final credential, then putOAuthCredential(credential) returned an error while writing it to the credential store.
Common situations: Disk full or read-only workspace; permission changes on the data directory; storage corruption; concurrent write conflicts on the credential store.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- save OAuth client registration
- agent context cannot be compacted enough: persist compaction
- configuration is not initialized
- discover OAuth authorization server
- exchange OAuth authorization code
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/fbead83d8d9bc82c.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/mcp/client/oauth.go:414
token, err := config.Exchange(exchangeCtx, callback.Code,
oauth2.VerifierOption(verifier),
oauth2.SetAuthURLParam("resource", prm.Resource))
if err != nil {
return fmt.Errorf("exchange OAuth authorization code: %w", err)
}
if token.TokenType != "" && !strings.EqualFold(token.TokenType, "Bearer") {
return fmt.Errorf("OAuth token endpoint returned unsupported token type %q", token.TokenType)
}
credential = registrationCredential
credential.TokenAuthMethod = authMethod
credential.AccessToken = token.AccessToken
credential.RefreshToken = token.RefreshToken
credential.TokenType = token.TokenType
credential.Expiry = token.Expiry
credential.Scopes = scopes
credential.Rejected = false
if err = putOAuthCredential(credential); err != nil {
return fmt.Errorf("save OAuth credentials: %w", err)
}
h.sourceMu.Lock()
h.source = &storedOAuthTokenSource{credential: credential, client: h.client}
h.sourceMu.Unlock()
setMCPRuntimeStateForContext(ctx, h.server.ID, "oauth_retrying", 0, "", "")
return nil
}
func hasBearerChallenge(challenges []oauthex.Challenge) bool {
for _, challenge := range challenges {
if strings.EqualFold(challenge.Scheme, "bearer") {
return true
}
}
return false
}
func bearerChallengeParam(challenges []oauthex.Challenge, name string) string {View on GitHub (pinned to 9f775e8a12)