{"record":{"id":"05298e90d0efdde4","repo":"apache/pulsar","slug":"protobuf-root-message-change-is-not-allowed-under","errorCode":null,"errorMessage":"Protobuf root message change is not allowed under the '%s' strategy. Original message name: '%s', new message name: '%s'.","messagePattern":"Protobuf root message change is not allowed under the '(.+?)' strategy\\. Original message name: '(.+?)', new message name: '(.+?)'\\.","errorType":"exception","errorClass":"IncompatibleSchemaException","httpStatus":null,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/service/schema/ProtobufNativeSchemaCompatibilityCheck.java","lineNumber":70,"sourceCode":"            case ALWAYS_COMPATIBLE:\n                return;\n            default:\n                throw new IncompatibleSchemaException(\"Unknown SchemaCompatibilityStrategy.\");\n        }\n    }\n\n    @Override\n    public void checkCompatible(Iterable<SchemaData> from, SchemaData to, SchemaCompatibilityStrategy strategy)\n            throws IncompatibleSchemaException {\n        for (SchemaData schemaData : from) {\n            checkCompatible(schemaData, to, strategy);\n        }\n    }\n\n    private void checkRootMessageChange(Descriptor fromDescriptor, Descriptor toDescriptor,\n                                            SchemaCompatibilityStrategy strategy) throws IncompatibleSchemaException {\n        if (!fromDescriptor.getFullName().equals(toDescriptor.getFullName())) {\n            throw new IncompatibleSchemaException(\"Protobuf root message change is not allowed under the '\"\n                    + strategy + \"' strategy. Original message name: '\" + fromDescriptor.getFullName()\n                    + \"', new message name: '\" + toDescriptor.getFullName() + \"'.\");\n        }\n    }\n\n}\n","sourceCodeStart":52,"sourceCodeEnd":77,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/schema/ProtobufNativeSchemaCompatibilityCheck.java#L52-L77","documentation":"Under BACKWARD, FORWARD, or FULL strategies, a Protobuf Native schema may not change its root message's full name: the descriptor of the new schema must resolve to the same fully-qualified message name as the existing one. Renaming or moving the root message breaks wire/semantic identity for existing consumers, so it is rejected.","triggerScenarios":"checkRootMessageChange invoked from checkCompatible when fromDescriptor.getFullName() != toDescriptor.getFullName() — e.g. the .proto root message was renamed, repackaged (package change alters the full name), or a different message was chosen as the schema root.","commonSituations":"Refactoring a proto package (com.old.Msg -> com.new.Msg) without realizing the full name changes; renaming the root message class; uploading a schema generated from a different root message while consumers still use the old one.","solutions":["Keep the root message's package and name identical; undo the rename in the .proto file and regenerate the descriptor.","If the rename is required, delete the topic schema and re-register the new schema (coordinate so consumers fetch the new schema).","Set strategy to ALWAYS_COMPATIBLE only if you truly accept unvalidated root-message changes."],"exampleFix":"// before\npackage com.old; message Event { ... } // full name com.old.Event\n// after\npackage com.old; message Event { ... } // unchanged root; evolve fields only\n// or new root: message EventV2 { ... } in a NEW topic schema registration","handlingStrategy":"validation","validationCode":"Descriptor from = existingProtoDescriptor;\nDescriptor to = newProtoDescriptor;\nif (!from.getFullName().equals(to.getFullName())) {\n    throw new IllegalArgumentException(\"Protobuf root message changed: \" + from.getFullName() + \" -> \" + to.getFullName());\n}","typeGuard":"boolean sameRootMessage(Descriptor a, Descriptor b) {\n    return a != null && b != null && a.getFullName().equals(b.getFullName());\n}","tryCatchPattern":"try {\n    admin.schemas().createSchema(topic, protoNativeSchemaInfo);\n} catch (PulsarAdminException e) {\n    if (e.getMessage().contains(\"Protobuf root message change is not allowed\")) {\n        // restore original message/package name or re-register schema deliberately\n    }\n}","preventionTips":["Treat proto package and root message name as immutable once registered.","Never rename the root message to 'evolve' a schema; add fields instead.","Run a CI check comparing descriptor full names against the deployed topic schema.","For genuine renames, plan a new topic and consumer migration."],"tags":["pulsar","protobuf","root-message-change"],"backgroundTag":"protobuf-root-message-change","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}