siyuan-note/siyuan · error

save OAuth credentials: %w

Error message

save OAuth credentials: %w

What it means

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.

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 251596fc0d)

Solutions

  1. Check the wrapped error's filesystem errno and resolve space/permissions on the kernel data directory.
  2. Ensure single-instance operation (no second SiYuan holding the workspace lock).
  3. After resolving the storage issue, re-run authorization — the in-memory source was not installed (h.source set only after a successful save).
Defensive patterns

Strategy: try-catch

Try / catch

if err = putOAuthCredential(credential); err != nil {
    // Final token obtained but not persisted; user must re-authorize after storage is fixed.
    logging.LogErrorf("mcp oauth: persist credentials failed: %s", err)
    return fmt.Errorf("save OAuth credentials: %w", err)
}

Prevention

When it happens

Trigger: 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.

Common situations: Disk full; keystore file locked by another process; permissions revoked on the data directory; keystore corruption; AV locking the credential file on Windows.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/fbead83d8d9bc82c. Report an issue: GitHub.