ory/hydra · error
read file: %s
Error message
read file: %s
What it means
FetchBytes dispatches on the source URI scheme. For file:// sources it calls os.ReadFile; any OS-level failure (missing file, permission denied, is-a-directory) is wrapped with 'read file: <redacted path>'.
Source
Thrown at oryx/fetcher/fetcher.go:130
}
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))
}
}
func (f *Fetcher) fetchRemote(ctx context.Context, source string) (b []byte, err error) {
if f.cache != nil {
cacheKey := sha256.Sum256([]byte(source))
if v, ok := f.cache.Get(cacheKey[:]); ok {
b = make([]byte, len(v))View on GitHub (pinned to 4174065ffb)
Solutions
- Verify the file exists at the exact path in the file:// URL (ls/stat it from the running environment).
- Fix permissions so the process user can read the file, and ensure it is a regular file, not a directory.
- In containers/k8s, mount the file into the container at the referenced path.
- Use an absolute path: file:///etc/ory/jwks.json, not file://etc/ory/jwks.json.
Example fix
// before fetcher.FetchContext(ctx, "file://config/keys.json") // relative, file not found // after fetcher.FetchContext(ctx, "file:///etc/ory/config/keys.json")
Defensive patterns
Strategy: validation
Validate before calling
func validateFileSource(source string) error {
if !strings.HasPrefix(source, "file://") {
return nil
}
path := strings.TrimPrefix(source, "file://")
if !filepath.IsAbs(path) {
return fmt.Errorf("file source must be absolute: %s", source)
}
fi, err := os.Stat(path)
if err != nil {
return err
}
if fi.IsDir() {
return fmt.Errorf("file source is a directory: %s", path)
}
return nil
} Try / catch
b, err := f.FetchContext(ctx, source)
if err != nil && strings.HasPrefix(err.Error(), "read file:") {
log.Printf("config file unreadable, check existence/permissions: %v", err)
os.Exit(1)
} Prevention
- Always use absolute paths in file:// URLs.
- Check file existence and permissions at application startup, not lazily.
- In containers, verify the file is mounted and readable by the process user.
When it happens
Trigger: Calling FetchContext/FetchBytes with a file:// URL whose path does not exist, lacks read permission, points to a directory, or has a malformed path (e.g. file://relative/path or trailing whitespace).
Common situations: Config files referencing JWK/keys via file:// URLs that were moved or deleted; running in a container where the file was not mounted; permission differences between dev and prod environments.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- unable to open file %q: %w
- %w: in source %q: allowed schemes: %s
- file watch: %v
- base64decode: %s
- NewRestore failed
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/4f81df9e749e765d.
Report an issue: GitHub.