siyuan-note/siyuan · error
OAuth authorization server metadata not found
Error message
OAuth authorization server metadata not found
What it means
Returned by mcpOAuthHandler.Authorize when auth.GetAuthServerMetadata completed without an error but returned a nil metadata object. The SDK treats nil-with-nil-err as a possible outcome (e.g. a successful HTTP response that decoded to nothing usable), and SiYuan treats it as a hard failure because subsequent steps dereference asm fields.
Source
Thrown at kernel/mcp/client/oauth.go:217
if interactive {
defer func() {
if retErr != nil && !errors.Is(retErr, context.Canceled) {
setMCPRuntimeStateForContext(ctx, h.server.ID, "authorization_required", 0, retErr.Error(), "")
}
}()
}
prm, err := discoverProtectedResource(ctx, challenges, req.URL.String(), h.client)
if err != nil {
return err
}
asm, err := auth.GetAuthServerMetadata(ctx, prm.AuthorizationServers[0], h.client)
if err != nil {
return fmt.Errorf("discover OAuth authorization server: %w", err)
}
if asm == nil {
return fmt.Errorf("OAuth authorization server metadata not found")
}
credential, hasCredential := getOAuthCredential(h.server.ID, h.server.URL)
if hasCredential && credential.Issuer == asm.Issuer {
credential.TokenEndpoint = asm.TokenEndpoint
credential.RevocationEndpoint = asm.RevocationEndpoint
}
if hasCredential && credential.Issuer == asm.Issuer && credential.RefreshToken != "" &&
challengeError != "insufficient_scope" && !credential.Rejected && !oauthClientRegistrationExpired(credential) {
refreshed, permanent, refreshErr := refreshOAuthCredential(ctx, h.client, credential)
if refreshErr == nil {
if saveErr := putOAuthCredential(refreshed); saveErr != nil {
logging.LogWarnf("mcp oauth: save refreshed credentials failed: %s", saveErr)
}
h.sourceMu.Lock()
h.source = &storedOAuthTokenSource{credential: refreshed, client: h.client}
h.sourceMu.Unlock()
setMCPRuntimeStateForContext(ctx, h.server.ID, "oauth_retrying", 0, "", "")
return nilView on GitHub (pinned to 251596fc0d)
Solutions
- curl the metadata URL and confirm it returns a non-empty JSON object containing at minimum 'issuer', 'authorization_endpoint', 'token_endpoint'.
- Ensure the auth server's metadata endpoint sets Content-Type: application/json and a parseable body.
- If the body is correct but nil is still returned, capture the go-sdk version and report the regression with the metadata payload.
- As a workaround for a broken auth server, use static Authorization headers instead of OAuth.
Defensive patterns
Strategy: validation
Validate before calling
// Fetch the metadata document and assert it is non-empty JSON with an issuer.
func probeMetadata(ctx context.Context, url string) error {
// GET url; json-decode; require Issuer != ""
return nil
} Prevention
- Confirm the metadata endpoint returns Content-Type: application/json and a non-empty body.
- If the auth server is a stub, switch to static Authorization headers.
When it happens
Trigger: auth.GetAuthServerMetadata(ctx, prm.AuthorizationServers[0], h.client) returns (nil, nil). The HTTP request succeeded but no metadata was materialized — empty 200 body, a non-JSON content type that the SDK silently skipped, or an SDK edge case.
Common situations: Auth server returned 200 with an empty body or HTML error page; content-type mismatch caused the SDK to skip decoding; auth server is a stub that responds 200 to everything; SDK version regression returning nil unexpectedly.
Related errors
- discover OAuth authorization server: %w
- OAuth authorization server does not support PKCE S256
- OAuth authorization server does not support the authorizatio
- OAuth authorization server does not support the authorizatio
- OAuth authorization server does not support dynamic client r
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/8732c50d6b653d71.
Report an issue: GitHub.