ory/kratos · error

$ref scheme is not permitted in identity schemas

Error message

$ref scheme %q is not permitted in identity schemas

What it means

After parsing a $ref URL, loadRefURL enforces that only the "base64" scheme is allowed for identity schemas; any other scheme (file://, http://, https://, etc.) is rejected with this error. This prevents identity schemas from pulling in arbitrary local or remote resources, closing a data-exfiltration/SSRF vector.

Solutions

  1. Inline the referenced schema directly into the identity schema instead of using a $ref to an external URL.
  2. Convert the referenced schema content to a base64 data reference using the permitted scheme: base64://<url-safe base64 of the schema JSON>.
  3. Remove file:// and http(s):// $refs entirely — they are deliberately blocked; only the base64 scheme is allowlisted.
  4. If tooling generates schemas with external refs, change the generator to emit base64:// refs or embed subschemas via definitions/$defs.

Example fix

// before
"$ref": "file:///schemas/address.json"
// after
"$ref": "base64://eyJ0eXBlIjoib2JqZWN0In0="  (or inline the schema under $defs and use "#/definitions/address")
Defensive patterns

Strategy: validation

Validate before calling

u, _ := url.Parse(ref)
if u != nil && u.Scheme != "base64" {
    return fmt.Errorf("$ref %q must use base64:// scheme", ref)
}

Try / catch

if strings.Contains(err.Error(), "is not permitted in identity schemas") {
    // inline the schema or convert to base64:// ref
}

Prevention

When it happens

Trigger: An identity schema contains a $ref with a non-base64 scheme, e.g. "file:///etc/passwd" or "https://example.com/schema.json". Raised during identity schema compilation whenever the registered loadRefURL loader resolves a ref whose u.Scheme != "base64".

Common situations: Operators reusing schemas written for generic JSON Schema tooling where file:// or https:// refs are normal; schemas migrated from environments without scheme restrictions; attempts to reference local helper schemas during development.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at schema/loader.go:35

	"github.com/pkg/errors"

	"github.com/ory/jsonschema/v3"
	"github.com/ory/x/httpx"
)

// loadRefURL resolves the URL of a `$ref` inside a schema. It enforces the
// scheme allowlist and then delegates to the jsonschema package's global
// loader table. The global `file` loader remains registered so that
// operator-configured top-level schema URLs (resolved outside the compiler)
// keep working.
func loadRefURL(ctx context.Context, raw string) (io.ReadCloser, error) {
	u, err := url.Parse(raw)
	if err != nil {
		return nil, fmt.Errorf("invalid $ref URL %q: %w", raw, err)
	}
	if u.Scheme != "base64" {
		return nil, fmt.Errorf("$ref scheme %q is not permitted in identity schemas", u.Scheme)
	}
	return jsonschema.LoadURL(ctx, raw)
}

// NewCompiler returns a jsonschema.Compiler. When disallowRefs is true, the
// compiler rejects `file://` URLs (and any other non-allowlisted scheme) in
// `$ref` values, preventing an attacker-supplied schema from reading local
// files on the Kratos host. When disallowRefs is false, the compiler uses
// the jsonschema library's default loader table, which preserves legacy
// behavior for operators who intentionally reference local files.
//
// The flag is controlled by `security.disallow_ref_in_identity_schemas`.
// Ory Network forces it on.
func NewCompiler(disallowRefs bool) *jsonschema.Compiler {
	c := jsonschema.NewCompiler()
	if disallowRefs {
		c.LoadURL = loadRefURL
	}

View on GitHub (pinned to b86338da04)