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

  1. Confirm the resource server still serves a valid PRM document at the stored ResourceMetadataURL (or the resource's well-known path).
  2. If the resource/issuer changed permanently, clear the stored OAuth credential so SiYuan re-runs full discovery and re-registration.
  3. 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

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


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