siyuan-note/siyuan · error
validate OAuth protected resource: %w
Error message
validate OAuth protected resource: %w
What it means
Wrapped error at oauth.go:521-523 from discoverProtectedResource during validateCredentialIssuer — the routine that confirms a stored credential's issuer is still valid before reuse. The underlying error is one of [335], [336], or a fetch failure, indicating the resource metadata for a previously-working credential can no longer be discovered.
Source
Thrown at kernel/mcp/client/oauth.go:523
}
if len(prm.AuthorizationServers) == 0 {
return nil, fmt.Errorf("OAuth protected resource metadata has no authorization server")
}
return &discoveredProtectedResource{ProtectedResourceMetadata: prm, MetadataURL: candidate.URL}, nil
}
return nil, fmt.Errorf("OAuth protected resource metadata not found")
}
func (h *mcpOAuthHandler) validateCredentialIssuer(ctx context.Context, credential oauthCredential) (bool, error) {
var challenges []oauthex.Challenge
resource := h.server.URL
if credential.ResourceMetadataURL != "" {
challenges = []oauthex.Challenge{{Scheme: "bearer", Params: map[string]string{"resource_metadata": credential.ResourceMetadataURL}}}
resource = credential.Resource
}
prm, err := discoverProtectedResource(ctx, challenges, resource, h.client)
if err != nil {
return false, fmt.Errorf("validate OAuth protected resource: %w", err)
}
if prm.Resource != credential.Resource || len(prm.AuthorizationServers) == 0 {
return false, nil
}
asm, err := auth.GetAuthServerMetadata(ctx, prm.AuthorizationServers[0], h.client)
if err != nil {
return false, fmt.Errorf("validate OAuth issuer: %w", err)
}
return asm != nil && asm.Issuer == credential.Issuer && asm.TokenEndpoint == credential.TokenEndpoint, nil
}
func protectedResourceURLs(metadataURL, resource string) []protectedResourceURL {
var result []protectedResourceURL
if metadataURL != "" {
result = append(result, protectedResourceURL{URL: metadataURL, Resource: resource})
}
resourceURL, err := url.Parse(resource)
if err != nil {View on GitHub (pinned to 251596fc0d)
Solutions
- Confirm the resource server still serves a valid PRM document at the stored ResourceMetadataURL (or the resource's well-known path).
- If the resource/issuer changed permanently, clear the stored OAuth credential so SiYuan re-runs full discovery and re-registration.
- Retry on transient network failures; for persistent failures, reconfigure the MCP server URL.
Defensive patterns
Strategy: retry
Try / catch
// validateCredentialIssuer failure during TokenSource — retry on transient outage.
valid, err := h.validateCredentialIssuer(ctx, credential)
if err != nil {
if isTransientNetworkErr(err) {
// Allow a short retry; do NOT discard the credential on a transient fetch failure.
return nil, nil // fall back to no token this cycle, retry next request
}
return nil, err
} Prevention
- Distinguish transient discovery failures from permanent resource changes; do not clear credentials on transient errors.
- Keep the resource server's PRM endpoint stable across restarts.
- When the resource/issuer changes permanently, clear stored OAuth credentials to force clean re-discovery.
When it happens
Trigger: TokenSource calls validateCredentialIssuer on a stored credential; discoverProtectedResource fails (PRM missing, no auth server, or network). The credential is then treated as unusable for that request.
Common situations: Resource server moved or dropped RFC 9728 support since the credential was issued; transient network outage to the resource; resource_metadata URL stored on the credential is now 404; AS rotated and the resource no longer advertises it.
Related errors
- validate OAuth issuer: %w
- OAuth protected resource metadata has no authorization serve
- OAuth protected resource metadata not found
- tools/list returned an empty response
- tools/list repeated cursor %q
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/4099c98f9273ef9d.
Report an issue: GitHub.