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

  1. Prefix the source with an allowed scheme: file:///abs/path.json or https://host/jwks.json
  2. Update the fetcher/client config to allow the needed scheme (e.g. enable file:// scheme)
  3. Fix typos in the scheme (htp:// -> https://)
  4. 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

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


AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03). Data as JSON: /api/errors/81a803d8221e8c39. Report an issue: GitHub.