{"record":{"id":"536d15bc3288baa4","repo":"apache/pulsar","slug":"incompatible-schema-expected-avro-schema-format-f","errorCode":null,"errorMessage":"Incompatible schema: expected Avro schema format for SchemaType.JSON","messagePattern":"Incompatible schema: expected Avro schema format for SchemaType\\.JSON","errorType":"exception","errorClass":"IncompatibleSchemaException","httpStatus":null,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/service/schema/JsonSchemaCompatibilityCheck.java","lineNumber":65,"sourceCode":"     * Set whether to allow legacy Jackson JsonSchema format for backward compatibility.\n     * When false (default), only valid Avro schema format is accepted (PIP-464).\n     */\n    public void setAllowLegacyJacksonFormat(boolean allowLegacyJacksonFormat) {\n        this.allowLegacyJacksonFormat = allowLegacyJacksonFormat;\n    }\n\n    @Override\n    public void checkCompatible(SchemaData from, SchemaData to, SchemaCompatibilityStrategy strategy)\n            throws IncompatibleSchemaException {\n        if (isAvroSchema(from)) {\n            if (isAvroSchema(to)) {\n                // if both producer and broker have the schema in avro format\n                super.checkCompatible(from, to, strategy);\n            } else if (allowLegacyJacksonFormat && isJsonSchema(to)) {\n                // if broker have the schema in avro format but producer sent a schema in the old json format\n                // allow old schema format for backwards compatibility (only when legacy format is enabled)\n            } else {\n                throw new IncompatibleSchemaException(\n                        \"Incompatible schema: expected Avro schema format for SchemaType.JSON\");\n            }\n        } else if (allowLegacyJacksonFormat && isJsonSchema(from)) {\n\n            if (isAvroSchema(to)) {\n                // if broker have the schema in old json format but producer sent a schema in the avro format\n                // return true and overwrite the old format\n            } else if (isJsonSchema(to)) {\n                // if both producer and broker have the schema in old json format\n                isCompatibleJsonSchema(from, to);\n            } else {\n                throw new IncompatibleSchemaException(\n                        \"Incompatible schema: expected Avro schema format for SchemaType.JSON\");\n            }\n        } else if (!allowLegacyJacksonFormat && !isAvroSchema(from)) {\n            // When legacy format is disabled, the existing schema must be valid Avro.\n            // If it's not, this is a defense-in-depth rejection (PIP-464).\n            throw new IncompatibleSchemaException(","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/schema/JsonSchemaCompatibilityCheck.java#L47-L83","documentation":"JsonSchemaCompatibilityCheck requires JSON schemas to be stored in Avro format. This error is thrown in the checkCompatible(Iterable, SchemaData, strategy) path when the existing broker schema is Avro-formatted JSON, but the incoming schema is neither a valid Avro schema nor a legacy Jackson JsonSchema (or the legacy format is disabled).","triggerScenarios":"Updating a topic schema where the stored schema is an Avro-format JSON schema and the new uploaded schema fails both isAvroSchema(to) and (allowLegacyJacksonFormat && isJsonSchema(to)).","commonSituations":"A producer built against an old Pulsar client sends the legacy Jackson JSON schema representation to a broker where allowLegacyJacksonFormat is false or the payload is simply malformed; or a hand-edited schema JSON string is uploaded that is neither valid Avro nor a valid JsonSchema document.","solutions":["Send the schema as a valid Avro schema (e.g. via Schema.JSON(...).getSchemaInfo() on a modern client that serializes to Avro).","If legacy Jackson-format clients must be supported, enable the legacy JSON schema format option on the broker (allowLegacyJacksonFormat).","Validate the schema payload parses as Avro before uploading."],"exampleFix":"// before: legacy Jackson JSON schema on Avro-only broker\nSchemaInfo info = SchemaInfoImpl.builder().schema(jsonBytesOfJacksonSchema).type(SchemaType.JSON)...;\n// after: Avro-encoded JSON schema\nSchemaInfo info = Schema.JSON(Pojo.class).getSchemaInfo();","handlingStrategy":"validation","validationCode":"try (Schema.Parser p = new Schema.Parser()) {\n    p.parse(new String(schemaBytes, StandardCharsets.UTF_8)); // throws if not Avro\n}\n// or verify JsonSchema legacy shape only if allowLegacyJacksonFormat is enabled","typeGuard":"boolean isAvroJsonSchema(byte[] data) {\n    try { new org.apache.avro.Schema.Parser().parse(new String(data, java.nio.charset.StandardCharsets.UTF_8)); return true; }\n    catch (Exception e) { return false; }\n}","tryCatchPattern":"try {\n    admin.schemas().createSchema(topic, schemaInfo);\n} catch (PulsarAdminException e) {\n    if (e.getMessage().contains(\"expected Avro schema format for SchemaType.JSON\")) {\n        schemaInfo = Schema.JSON(MyPojo.class).getSchemaInfo(); // regenerate in Avro format\n    }\n}","preventionTips":["Use Schema.JSON(Pojo.class) from a current Pulsar client so schema payloads are Avro-encoded.","Do not hand-write JSON schema definition bytes.","Plan the migration window where allowLegacyJacksonFormat is still enabled before disabling it.","Test schema uploads in a staging namespace before production."],"tags":["pulsar","json-schema","avro"],"backgroundTag":"json-schema-format-mismatch","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}