zed-industries/zed · error

Protected Resource Metadata at {} has no authorization_serve

Error message

Protected Resource Metadata at {} has no authorization_servers

What it means

During OAuth discovery, Zed successfully fetched a Protected Resource Metadata document (RFC 9724) but its authorization_servers array is empty. That array is the only way discovery learns where to continue, so an otherwise valid JSON document with zero entries is treated as a hard error rather than silently trying nothing. The bail happens inside the loop over candidate URLs on the first fetch that succeeds.

Source

Thrown at crates/context_server/src/oauth.rs:776

            urls
        }
        Some(url) => {
            log::warn!(
                "Ignoring cross-origin resource_metadata URL {} \
                 (server origin: {})",
                url,
                server_url.origin().unicode_serialization()
            );
            protected_resource_metadata_urls(server_url)
        }
        None => protected_resource_metadata_urls(server_url),
    };

    for url in &candidate_urls {
        match fetch_json::<ProtectedResourceMetadataResponse>(http_client, url).await {
            Ok(response) => {
                if response.authorization_servers.is_empty() {
                    bail!(
                        "Protected Resource Metadata at {} has no authorization_servers",
                        url
                    );
                }
                return Ok(ProtectedResourceMetadata {
                    resource: response.resource.unwrap_or_else(|| server_url.clone()),
                    authorization_servers: response.authorization_servers,
                    scopes_supported: response.scopes_supported,
                });
            }
            Err(err) => {
                log::debug!(
                    "Failed to fetch Protected Resource Metadata from {}: {}",
                    url,
                    err
                );
            }
        }

View on GitHub (pinned to f4178619ac)

Solutions

  1. Set authorization_servers to a non-empty array containing the issuer URL of your OAuth authorization server, e.g. ["https://auth.example.com"]
  2. Validate the deployed document with curl https://server/.well-known/oauth-protected-resource and a JSON schema check for RFC 9724 fields
  3. If you intended the resource to be its own authorization server, list its own issuer URL in the array rather than leaving it empty

Example fix

// before
{ "resource": "https://mcp.example.com",
  "authorization_servers": [] }

// after
{ "resource": "https://mcp.example.com",
  "authorization_servers": ["https://auth.example.com"] }
Defensive patterns

Strategy: validation

Validate before calling

// client-side: verify the document before feeding discovery
async fn check_prm_document(http: &Arc<dyn HttpClient>, url: &Url) -> Result<bool> {
    let doc: serde_json::Value = fetch_json(http, url).await?;
    Ok(doc.get("authorization_servers")
        .and_then(|v| v.as_array())
        .is_some_and(|a| !a.is_empty()))
}

Type guard

fn prm_has_auth_servers(doc: &serde_json::Value) -> bool {
    doc.get("authorization_servers")
        .and_then(|v| v.as_array())
        .is_some_and(|a| !a.is_empty())
}

Try / catch

match fetch_protected_resource_metadata(&client, &server_url, &challenge).await {
    Err(err) if err.to_string().contains("no authorization_servers") => {
        // fetched fine but empty — fix the served document; retrying will not help until it changes
        report_server_config_issue(&server_url, "authorization_servers is empty");
        Err(err)
    }
    other => other,
}

Prevention

When it happens

Trigger: fetch_protected_resource_metadata() gets a 2xx JSON response whose authorization_servers is [] (or missing and defaulted to empty). Typical when a hand-written .well-known/oauth-protected-resource file was deployed with the field omitted or set to an empty list.

Common situations: First-time setup of a Protected Resource Metadata file where the author forgot to list their authorization server; tooling that generates the document with a placeholder empty array; a test fixture copied from a partial example; accidentally pointing authorization_servers at the resource's own URL with a typo that made deserialization drop it.

Related errors


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/e2892859475ea59a. Report an issue: GitHub.