{"record":{"id":"0f513f3ae9619626","repo":"quarkusio/quarkus","slug":"cannot-resolve-schema-with-refs","errorCode":null,"errorMessage":"Cannot resolve schema  with refs ","messagePattern":"Cannot resolve schema  with refs ","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/schema-registry/confluent/json-schema/runtime/src/main/java/io/quarkus/confluent/registry/json/runtime/graal/ConfluentJsonSubstitutions.java","lineNumber":52,"sourceCode":"        }\n\n        Class<?> cls = object.getClass();\n        //We only support the scenario of having the schema defined in the annotation in the java bean, since it does not rely on outdated libraries.\n        if (cls.isAnnotationPresent(Schema.class)) {\n            Schema schema = cls.getAnnotation(Schema.class);\n            List<SchemaReference> references = Arrays.stream(schema.refs())\n                    .map(new Function<io.confluent.kafka.schemaregistry.annotations.SchemaReference, SchemaReference>() {\n                        @Override\n                        public SchemaReference apply(\n                                io.confluent.kafka.schemaregistry.annotations.SchemaReference schemaReference) {\n                            return new SchemaReference(schemaReference.name(), schemaReference.subject(),\n                                    schemaReference.version());\n                        }\n                    })\n                    .collect(Collectors.toList());\n            if (client == null) {\n                if (!references.isEmpty()) {\n                    throw new IllegalArgumentException(\"Cannot resolve schema \" + schema.value()\n                            + \" with refs \" + references);\n                }\n                return new JsonSchema(schema.value());\n            } else {\n                return (JsonSchema) client.parseSchema(JsonSchema.TYPE, schema.value(), references)\n                        .orElseThrow(new Supplier<IOException>() {\n                            @Override\n                            public IOException get() {\n                                return new IOException(\"Invalid schema \" + schema.value()\n                                        + \" with refs \" + references);\n                            }\n                        });\n            }\n        }\n        return null;\n    }\n}\n","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/schema-registry/confluent/json-schema/runtime/src/main/java/io/quarkus/confluent/registry/json/runtime/graal/ConfluentJsonSubstitutions.java#L34-L70","documentation":"During native-image substitution, Quarkus replaces the Confluent Schema Registry client's schema-parsing path with a local fallback. When no client is configured and there are schema references, the substituted code cannot resolve the referenced schemas, so it throws. The library throws this because resolving refs requires the schema registry client, which is absent.","triggerScenarios":"Building/running a native image (or using the Confluent JSON Schema substitution path) while deserializing/serializing JSON Schema messages whose schema declares references ($ref/$defs to other registered schemas) with quarkus.registry.confluent.* client disabled or not on the classpath.","commonSituations":"Avro/JSON Schema topics using schema references produced via Confluent SR ('register schema with references'); the app only declares quarkus-apicurio-registry-avro or forgot the confluent registry dependency; refs work in JVM mode but fail in native mode.","solutions":["Add the Confluent Schema Registry client dependency and configure quarkus.registry.confluent.schema-certification.url / registry client so the client is non-null","Avoid schema references in the JSON Schema subject, or inline the referenced schemas ($defs) into a single self-contained schema","If references are unavoidable, ensure the registries client (apicurio-registry-schema-registry-json-serde with client support) is used rather than the substitution fallback","Check that the serializer/deserializer config points at the correct Schema Registry URL and the referenced schemas are registered there"],"exampleFix":"// before (application.properties)\n# no registry client configured\nmp.messaging.connector.smallrye-kafka.schema.registry.url=http://localhost:8081\n// after\nquarkus.registry.confluent.schema-certification.url=http://localhost:8081\nquarkus.apicurio-registry.json.confluent-id-strategy=Legacy4Byte\n# or inline refs:\n// before: {\"$ref\":\"other.schema.json\"}\n// after: {\"$defs\": {\"Other\": {...}}, \"properties\": {\"o\": {\"$ref\":\"#/$defs/Other\"}}}","handlingStrategy":"validation","validationCode":"if (schema.getReferences() != null && !schema.getReferences().isEmpty()\n        && registryClient == null) {\n    throw new IllegalStateException(\n        \"JSON schema \" + schema.value() + \" has references but no registry client is configured; \"\n        + \"add the Confluent registry client dependency or inline the referenced schemas.\");\n}","typeGuard":"boolean isResolvable(JsonSchema schema) {\n    return schema.getReferences() == null\n        || schema.getReferences().isEmpty()\n        || registryClient != null;\n}","tryCatchPattern":null,"preventionTips":["Keep JSON Schemas self-contained (inline $defs) when possible","Verify registry client config (quarkus.registry.confluent.*) before deploying to native","Test schema resolution in a native-image integration test, not just JVM mode","Confirm referenced schemas are actually registered in the Schema Registry subject"],"tags":["schema-registry","json-schema","native-image","graal-substitution"],"backgroundTag":"unresolved-schema-ref","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}