cloudflare/cloudflared · error
failed to find Access application at %s
Error message
failed to find Access application at %s
What it means
fetchMetadataJWT performs an HTTP GET to the Access metadata endpoint and expects the response to carry the raw JWT in the `cf-access-metadata` header. If the response succeeds but the header is missing or empty, it means the requested URL is not served by a Cloudflare Access application, so there is no metadata token to return; the function fails with this error naming the requested URL.
Source
Thrown at token/token.go:502
Timeout: time.Second * 7,
}
req, err := http.NewRequest("HEAD", reqURL, nil)
if err != nil {
return "", errors.Wrap(err, "failed to create app info request")
}
req.Header.Set(accessMetadataReqHeader, accessMetadataReqValue)
req.Header.Set(userAgentHeader, userAgent)
resp, err := client.Do(req) // nolint: gosec
if err != nil {
return "", errors.Wrap(err, "failed to get app info")
}
_ = resp.Body.Close()
rawJWT := resp.Header.Get(accessMetadataRespHeader)
if rawJWT == "" {
return "", fmt.Errorf("failed to find Access application at %s", reqURL)
}
return rawJWT, nil
}
func validateMetadataIssuedAt(iat int64, now time.Time) error {
if iat <= 0 {
return errors.New("metadata JWT iat is missing or invalid")
}
issuedAt := time.Unix(iat, 0)
if issuedAt.Before(now.Add(-metadataMaxAge)) {
return fmt.Errorf("metadata JWT is older than %s", metadataMaxAge)
}
if issuedAt.After(now.Add(metadataAllowedClockSkew)) {
return fmt.Errorf("metadata JWT is more than %s in the future", metadataAllowedClockSkew)
}
return nil
}
View on GitHub (pinned to 2253eeeb25)
Solutions
- Confirm the URL is actually protected by a Cloudflare Access self-hosted application for that team domain.
- Check the URL for typos, wrong scheme, or redirects that land on a different host.
- Verify network egress reaches Cloudflare directly (no proxy stripping the cf-access-metadata header).
- Re-create or fix the Access application binding in the Zero Trust dashboard if the app was recently deleted or its domain changed.
- Add debug logging of resp.Header to inspect what the metadata endpoint actually returned.
Example fix
// before
rawJWT := resp.Header.Get(accessMetadataRespHeader)
// after (caller-side guard before calling GetAppInfo)
if !strings.Contains(appURL, "cloudflareaccess") && !isAccessProtected(appURL) {
return nil, errors.New("URL is not behind Cloudflare Access; skip GetAppInfo")
}
appInfo, err := token.GetAppInfo(authDomain, appURL) Defensive patterns
Strategy: validation
Validate before calling
// pre-flight: check the header exists before calling GetAppInfo
resp, err := http.Get(appURL)
if err != nil { return err }
if resp.Header.Get("cf-access-metadata") == "" {
return fmt.Errorf("%s is not behind Cloudflare Access (no cf-access-metadata header)", appURL)
} Try / catch
appInfo, err := token.GetAppInfo(authDomain, appURL)
if err != nil {
if strings.Contains(err.Error(), "failed to find Access application") {
return fmt.Errorf("%w — confirm the Access app exists and covers this hostname", err)
}
return err
} Prevention
- Verify the hostname in the Cloudflare Zero Trust dashboard is bound to a self-hosted Access application.
- Avoid proxies/interceptors that strip custom response headers like cf-access-metadata.
- Watch for redirects: the final URL must still be the Access-protected host.
- Test with `cloudflared access curl <url>` first to confirm Access serves the hostname.
When it happens
Trigger: Calling GetAppInfo (directly or through login, curl, generateToken, sshGen) when the HTTP response has no cf-access-metadata header — the hostname is not behind Cloudflare Access, the request followed redirects to a non-Access page, or the edge returned an error/HTML login page instead of metadata.
Common situations: Typo in the app URL or pointing at a domain with no Access application; an expired/misconfigured Access app returning a normal page; network middleboxes stripping the custom header; hitting an Access service-auth (mTLS) app that does not emit metadata for this request.
Understand the failure class
Background: "empty response", "returned no data", "empty embeddings": what HTTP 200-with-empty-body errors mean across libraries — this error's family across 36 libraries.
Related errors
- failed to fetch JWKS from %s
- invalid token
- metadata JWT aud is empty
- metadata JWT iat is missing or invalid
- quick tunnel provisioning failed with status %d: %s
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/305ff4ea99c8200c.
Report an issue: GitHub.