apache/pulsar · error · IncompatibleSchemaException

Incompatible Schema from %s + to %s

Error message

Incompatible Schema from %s + to %s

What it means

When both the existing and the new JSON schemas are in the legacy Jackson format, compatibility is decided by comparing their JSON 'id' fields; if the ids differ the schemas are considered incompatible and the full schema payloads are included in the error message.

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/service/schema/JsonSchemaCompatibilityCheck.java:99

            // When legacy format is disabled, the existing schema must be valid Avro.
            // If it's not, this is a defense-in-depth rejection (PIP-464).
            throw new IncompatibleSchemaException(
                    "Incompatible schema: existing schema is not in valid Avro format for SchemaType.JSON");
        } else {
            // broker has schema format with unknown format
            // maybe corrupted?
            // return true to overwrite
        }
    }

    private static final ObjectReader JSON_SCHEMA_READER =
            ObjectMapperFactory.getMapper().reader().forType(JsonSchema.class);
    private void isCompatibleJsonSchema(SchemaData from, SchemaData to) throws IncompatibleSchemaException {
        try {
            JsonSchema fromSchema = JSON_SCHEMA_READER.readValue(from.getData());
            JsonSchema toSchema = JSON_SCHEMA_READER.readValue(to.getData());
            if (!fromSchema.getId().equals(toSchema.getId())) {
                throw new IncompatibleSchemaException(String.format("Incompatible Schema from %s + to %s",
                        new String(from.getData(), UTF_8), new String(to.getData(), UTF_8)));
            }
        } catch (IOException e) {
            throw new IncompatibleSchemaException(e);
        }
    }

    private boolean isAvroSchema(SchemaData schemaData) {
        try {

            Schema.Parser fromParser = new Schema.Parser(StructSchemaDataValidator.COMPATIBLE_NAME_VALIDATOR);
            fromParser.setValidateDefaults(false);
            Schema fromSchema = fromParser.parse(new String(schemaData.getData(), UTF_8));
            return true;
        } catch (Exception e) {
            return false;
        }
    }

View on GitHub (pinned to 820761864e)

Solutions

  1. Ensure all producers for the topic use POJOs that yield the same JsonSchema id (same schema definition).
  2. Re-register the topic schema with the new definition in Avro format (delete schema first if needed).
  3. Migrate off the legacy Jackson format to Avro-format JSON schemas so normal Avro compatibility checks apply.

Example fix

// before: different ids
JsonSchema a = new JsonSchema("com.x.A", "schema1"); // id: schema1
JsonSchema b = new JsonSchema("com.x.B", "schema2"); // id: schema2
// after: aligned id
admin.schemas().createSchema(topic, Schema.JSON(Pojo.class).getSchemaInfo());
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-compare legacy JsonSchema ids client-side
JsonSchema from = MAPPER.readValue(existingBytes, JsonSchema.class);
JsonSchema to = MAPPER.readValue(newBytes, JsonSchema.class);
if (!from.getId().equals(to.getId())) throw new IllegalArgumentException("JsonSchema id mismatch");

Type guard

boolean sameJsonSchemaId(JsonSchema a, JsonSchema b) {
    return a != null && b != null && a.getId() != null && a.getId().equals(b.getId());
}

Try / catch

try {
    admin.schemas().createSchema(topic, schemaInfo);
} catch (PulsarAdminException e) {
    if (e.getMessage().startsWith("Incompatible Schema from")) {
        // ids differ: register new schema version or use a new topic
    }
}

Prevention

When it happens

Trigger: checkCompatible -> isCompatibleJsonSchema with both schemas parseable as legacy Jackson JsonSchema documents whose getId() values are not equal.

Common situations: Two different POJOs (or the same POJO renamed/refactored) serialized with legacy clients uploading schemas to the same topic; teams reusing a topic across unrelated JSON message types.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/f8eab6934ff26634. Report an issue: GitHub.