{"record":{"id":"4e0e225317fcd817","repo":"apple/pkl","slug":"cannotrendersubtypeforprotobuf","errorCode":"cannotRenderSubtypeForProtobuf","errorMessage":"cannotRenderSubtypeForProtobuf","messagePattern":"cannotRenderSubtypeForProtobuf","errorType":"error_code","errorClass":"VmException","httpStatus":null,"severity":"error","filePath":"pkl-core/src/main/java/org/pkl/core/stdlib/protobuf/RendererNodes.java","lineNumber":406,"sourceCode":"            writePropertyName();\n            expectedName = Identifier.get(\"it_\" + computedName);\n            propertyPath.push(expectedName);\n            startMessage();\n          } else if (type instanceof ListingOrMappingTypeNode listingOrMappingType) {\n            hasCollection = true;\n            collectionType = listingOrMappingType.getValueTypeNode();\n          } else if (type instanceof ListTypeNode listType) {\n            hasCollection = true;\n            collectionType = listType.getElementTypeNode();\n          } else if (type instanceof MapTypeNode mapType) {\n            hasCollection = true;\n            collectionType = mapType.getValueTypeNode();\n          } else if (type instanceof SetTypeNode setType) {\n            hasCollection = true;\n            collectionType = setType.getElementTypeNode();\n          } else if (type instanceof NonFinalClassTypeNode) {\n            if (type.getVmClass() != clazz) {\n              throw new VmExceptionBuilder()\n                  .evalError(\"cannotRenderSubtypeForProtobuf\", type.getVmClass(), clazz)\n                  .build();\n            }\n          }\n        }\n      }\n      visit(value);\n      if (hasWrapper) {\n        endMessage();\n        var popped = propertyPath.pop();\n        assert popped == expectedName : \"Corrupted traversal stack.\";\n      } else if (hasCollection) {\n        collectionType = prevCollectionType;\n      }\n      var popped = propertyPath.pop();\n      assert name == popped : \"Corrupted traversal stack.\";\n    }\n","sourceCodeStart":388,"sourceCodeEnd":424,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-core/src/main/java/org/pkl/core/stdlib/protobuf/RendererNodes.java#L388-L424","documentation":"When rendering Pkl values to Protobuf, the renderer walks a class hierarchy and refuses if it encounters a value whose concrete class is a non-final subclass of the declared class being rendered. Protobuf rendering requires the exact class, so a value of a subtype that differs from the target class cannot be represented. The error names both the offending subtype and the expected class.","triggerScenarios":"Rendering (Protobuf output) a property whose declared type is a non-final class but whose runtime value is an instance of a different subclass of that class, e.g. a property typed as a base class holding a derived-class instance.","commonSituations":"Config modules using class hierarchies (e.g. a `Worker` base class with `SshWorker`/`K8sWorker` subtypes) rendered to Protobuf; polymorphic collections where elements have mixed concrete types.","solutions":["Change the property's declared type to the exact concrete class of the value so subtype and rendered class match","Use Protobuf `oneof`/separate properties per subtype instead of a polymorphic base-typed property","Choose a different output format (e.g. JSON/YAML/PBF) that supports subtyping via a converter"],"exampleFix":"// before\nworker: Worker = new SshWorker { host = \"h\" }  // SshWorker != Worker for Protobuf\n// after\nworker: SshWorker = new SshWorker { host = \"h\" }","handlingStrategy":"type-guard","validationCode":"// before rendering to protobuf, check the value's class equals the declared property type\nfunction isExactClass(value: Any, expected: Class): Boolean = value.getClass() == expected\nif (!isExactModulePolymorphicValues(module)) throw \"polymorphic values cannot be protobuf-rendered\"","typeGuard":"function rendersAsExactClass(value: Any, expected: Class): Boolean = value.getClass() == expected","tryCatchPattern":null,"preventionTips":["Avoid base-class-typed properties holding subclass instances in modules destined for Protobuf","Model polymorphism with oneof-like separate properties or a discriminator + entry Listing","Prefer final/concrete types for protobuf-rendered fields","Test rendering modules to protobuf in CI"],"tags":["protobuf","rendering","subtype","pkl"],"backgroundTag":"unsupported-operation","analyzedSha":"f3efcbfc9b60d30053b0536d664948d7aa1b8673","analyzedAt":"2026-09-08T13:10:45.570Z","contentChangedAt":"2026-09-08T13:10:45.570Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}