ory/kratos · error

could not read schema file

Error message

could not read schema file: %w

What it means

ReadSchema loads an identity JSON schema from a URI. For file:// URIs it reads the file from disk with os.ReadFile; if the OS open/read fails (missing file, permission denied, wrong path), the error is wrapped as "could not read schema file".

Solutions

  1. Verify the file exists at the exact absolute path (file:// + absolute path, e.g. file:///etc/kratos/identity.schema.json)
  2. Check read permissions for the process user
  3. In containers, confirm the schema is copied/mounted into the image or volume
  4. Check the wrapped inner error message — it names the exact OS-level cause (no such file, permission denied)

Example fix

// before
"identity_schemas": {"default": {"file://schemas/identity.schema.json"}}
// after
"identity_schemas": {"default": {"file:///etc/config/identity.schema.json"}}
Defensive patterns

Strategy: validation

Validate before calling

// Go: preflight a file:// schema URI
func schemaFileReadable(raw string) error {
	u, err := url.Parse(raw)
	if err != nil || u.Scheme != "file" {
		return fmt.Errorf("not a file URI: %s", raw)
	}
	path := u.Host + u.Path
	fi, err := os.Stat(path)
	if err != nil {
		return fmt.Errorf("schema file missing: %w", err)
	}
	if fi.IsDir() {
		return fmt.Errorf("schema path is a directory: %s", path)
	}
	f, err := os.Open(path)
	if err != nil {
		return fmt.Errorf("schema file not readable: %w", err)
	}
	return f.Close()
}

Try / catch

schema, err := h.ReadSchema(ctx, uri)
if err != nil {
	var pathErr *os.PathError
	if errors.As(err, &pathErr) {
		return fmt.Errorf("identity schema %s unreadable: %v — check path/permissions", uri, pathErr.Err)
	}
	return err
}

Prevention

When it happens

Trigger: Identity schema configured as file:///path/to/schema.json where the file does not exist, the path is wrong (note: only the default scheme's empty path yields ""), permission bits block the process, or the path is a directory.

Common situations: Relative path resolved against a different working directory in containers; config pointing at the dev machine path inside Docker; file deleted after mount; read-only filesystem or missing volume mount.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of ory/kratos@b86338da04 (2026-09-07). Data as JSON: /api/errors/b9aa679b8eddc2d1. Report an issue: GitHub.

Appendix: source

Thrown at schema/handler.go:236

		ss[i] = identitySchemaContainer{
			ID:     schema.ID,
			Schema: raw,
		}
	}

	x.PaginationHeader(w, *r.URL, int64(total), page, itemsPerPage)
	h.r.Writer().Write(w, r, ss)
}

func (h *Handler) ReadSchema(ctx context.Context, uri *url.URL) (data []byte, err error) {
	ctx, span := h.r.Tracer(ctx).Tracer().Start(ctx, "schema.Handler.ReadSchema")
	defer otelx.End(span, &err)

	switch uri.Scheme {
	case "file":
		data, err = os.ReadFile(uri.Host + uri.Path) //nolint:gosec
		if err != nil {
			return nil, errors.WithStack(fmt.Errorf("could not read schema file: %w", err))
		}
	case "base64":
		data, err = base64.StdEncoding.DecodeString(strings.TrimPrefix(uri.String(), "base64://"))
		if err != nil {
			return nil, errors.WithStack(fmt.Errorf("could not decode schema file: %w", err))
		}
	default:
		req, err := retryablehttp.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil)
		if err != nil {
			return nil, errors.WithStack(fmt.Errorf("could not create request: %w", err))
		}
		resp, err := h.r.HTTPClient(ctx).Do(req)
		if err != nil {
			return nil, errors.WithStack(herodot.ErrUpstreamError().WithReason("could not fetch schema").WithError(err.Error()).WithDetail("uri", uri))
		}
		defer func() { _ = resp.Body.Close() }()
		if resp.StatusCode != http.StatusOK {
			if resp.StatusCode == http.StatusNotFound {

View on GitHub (pinned to b86338da04)