ory/hydra · error
%w: in source %q: allowed schemes: %s
Error message
%w: in source %q: allowed schemes: %s
What it means
fetcher.FetchBytes validates the URL scheme against the fetcher's allowed scheme list (f.schemes) before fetching. If the source does not start with any allowed scheme (e.g. http://, https://, file://), it returns ErrUnknownScheme wrapped with the redacted source and the allowed schemes.
Source
Thrown at oryx/fetcher/fetcher.go:122
}
// FetchContext fetches the file contents from the source and allows to pass a
// context that is used for HTTP requests.
func (f *Fetcher) FetchContext(ctx context.Context, source string) (*bytes.Buffer, error) {
b, err := f.FetchBytes(ctx, source)
if err != nil {
return nil, err
}
return bytes.NewBuffer(b), nil
}
// FetchBytes fetches the file contents from the source and allows to pass a
// context that is used for HTTP requests.
func (f *Fetcher) FetchBytes(ctx context.Context, source string) ([]byte, error) {
if !slices.ContainsFunc(f.schemes, func(scheme string) bool {
return strings.HasPrefix(source, scheme+"://")
}) {
return nil, errors.WithStack(fmt.Errorf("%w: in source %q: allowed schemes: %s", ErrUnknownScheme, redactedSource(source), strings.Join(f.schemes, ", ")))
}
switch {
case strings.HasPrefix(source, "http://"), strings.HasPrefix(source, "https://"):
return f.fetchRemote(ctx, source)
case strings.HasPrefix(source, "file://"):
b, err := os.ReadFile(strings.TrimPrefix(source, "file://"))
if err != nil {
return nil, errors.Wrapf(err, "read file: %s", redactedSource(source))
}
return b, nil
case strings.HasPrefix(source, "base64://"):
src, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(source, "base64://"))
if err != nil {
return nil, errors.Wrapf(err, "base64decode: %s", redactedSource(source))
}
return src, nil
default:
return nil, errors.Wrap(ErrUnknownScheme, "unknown scheme in source: "+redactedSource(source))View on GitHub (pinned to 4174065ffb)
Solutions
- Prefix the source with an allowed scheme: file:///abs/path.json or https://host/jwks.json
- Update the fetcher/client config to allow the needed scheme (e.g. enable file:// scheme)
- Fix typos in the scheme (htp:// -> https://)
- Use an absolute path with file:// rather than a relative path
Example fix
// before f.FetchBytes(ctx, "/etc/keys/jwks.json") // after f.FetchBytes(ctx, "file:///etc/keys/jwks.json")
Defensive patterns
Strategy: validation
Validate before calling
if !strings.Contains(source, "://") {
return fmt.Errorf("source %q missing scheme", source)
} Type guard
// schemeSep = "://"
func schemeAllowed(src string, schemes []string) bool {
return slices.ContainsFunc(schemes, func(s string) bool { return strings.HasPrefix(src, s+schemeSep) })
} Try / catch
if _, err := f.FetchBytes(ctx, src); err != nil {
if errors.Is(err, fetcher.ErrUnknownScheme) {
log.Fatalf("add scheme to %q or enable it in fetcher config", src)
}
} Prevention
- Always include scheme in configured URLs
- Whitelist needed schemes explicitly in fetcher setup
- Never rely on path-only sources
When it happens
Trigger: Passing a source string to FetchBytes/FetchContext without a scheme prefix (e.g. "keys.json" or "/path/file.json" instead of "file:///path/file.json"), or a scheme disabled in the fetcher configuration (e.g. file:// when only http(s) is allowed).
Common situations: Config values like jwks URLs written without https://, users supplying bare file paths, environments where the fetcher was constructed with restricted allowed_schemes (common in Ory services for security), typos like htp://.
Related errors
- could not parse the endpoint URL "%s"
- unsupported source `%s`
- cookiex: purpose must be non-empty and must not contain a pi
- cookiex: at least one secret is required
- cookiex: max age must not be negative
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/81a803d8221e8c39.
Report an issue: GitHub.