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
- Set authorization_servers to a non-empty array containing the issuer URL of your OAuth authorization server, e.g. ["https://auth.example.com"]
- Validate the deployed document with curl https://server/.well-known/oauth-protected-resource and a JSON schema check for RFC 9724 fields
- 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
- Add a deploy-time JSON assertion that authorization_servers is a non-empty array of https URLs
- Smoke-test the whole discovery chain (401 -> PRM -> AS metadata) in CI for your MCP server
- Include the resource and scopes_supported fields while you are at it to catch adjacent metadata mistakes
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
- Could not fetch Protected Resource Metadata for {}
- Auth server metadata issuer mismatch: expected {}, got {}
- Could not fetch Authorization Server Metadata for {}
- authorization server does not advertise code_challenge_metho
- OAuth endpoint must use HTTPS (got {}://{})
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/e2892859475ea59a.
Report an issue: GitHub.