{"record":{"id":"eb9ef3f05b5c1b04","repo":"conductor-oss/conductor","slug":"cannot-map-non-scalar-map-key","errorCode":null,"errorMessage":"cannot map non-scalar map key: ","messagePattern":"cannot map non-scalar map key: ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/MapType.java","lineNumber":121,"sourceCode":"            method.endControlFlow();\n            method.addStatement(\"to.$L($L)\", javaMethodName(\"set\", field), mapName);\n        }\n    }\n\n    @Override\n    public TypeName resolveJavaProtoType() {\n        return ParameterizedTypeName.get(\n                (ClassName) getRawJavaType(),\n                getKeyType().getJavaProtoType(),\n                getValueType().getJavaProtoType());\n    }\n\n    @Override\n    public String getProtoType() {\n        AbstractType keyType = getKeyType();\n        AbstractType valueType = getValueType();\n        if (!(keyType instanceof ScalarType)) {\n            throw new IllegalArgumentException(\n                    \"cannot map non-scalar map key: \" + this.getJavaType());\n        }\n        return String.format(\"map<%s, %s>\", keyType.getProtoType(), valueType.getProtoType());\n    }\n}\n","sourceCodeStart":103,"sourceCodeEnd":127,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/MapType.java#L103-L127","documentation":"Thrown as IllegalArgumentException by MapType.getProtoType when the map's key type is not a ScalarType. Protobuf map fields only permit scalar keys (integral, bool, string), so a Map<CustomType, V> or Map<List, V> cannot be represented and protogen refuses to emit a proto map for it.","triggerScenarios":"A @ProtoMessage class has a field of type Map<K,V> where K is a non-scalar Java type (another message, a collection, Object). TypeMapper builds a MapType, and when getProtoType() renders the field it hits the guard.","commonSituations":"Modeling domain objects with composite keys (e.g., Map<SomeEnum, V> if the enum is not registered as scalar, or Map<MyMessage, V>); introducing a new keyed collection that the codegen does not support.","solutions":["Change the map key to a scalar: Map<String, V>, Map<Integer, V>, Map<Long, V>, or Map<Boolean, V>.","If a composite key is required, flatten it: convert Map<Composite,V> into a List<CompositeEntry> where CompositeEntry holds the key fields plus the value.","Register a scalar mapping via TypeMapper.addScalarType only if the key is genuinely a primitive-like type supported by proto."],"exampleFix":"// before\n@ProtoMessage public class OrderBook {\n    Map<Instrument, Integer> quantities; // Instrument is a message\n}\n// after\n@ProtoMessage public class OrderBook {\n    Map<String, Integer> quantitiesByInstrumentId;\n}","handlingStrategy":"validation","validationCode":"// Static design-time check: map keys must be scalar\nimport java.lang.reflect.Field;\nimport java.lang.reflect.ParameterizedType;\nimport java.util.Map;\nstatic void assertScalarMapKeys(Class<?> msg) {\n    for (Field f : msg.getDeclaredFields()) {\n        if (Map.class.isAssignableFrom(f.getType())) {\n            ParameterizedType pt = (ParameterizedType) f.getGenericType();\n            Class<?> keyClass = (Class<?>) pt.getActualTypeArguments()[0];\n            Set<Class<?>> scalars = Set.of(int.class, Integer.class, long.class, Long.class,\n                String.class, boolean.class, Boolean.class);\n            if (!scalars.contains(keyClass)) {\n                throw new IllegalStateException(\"Map key of \" + f + \" is non-scalar: \" + keyClass);\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Restrict protobuf map keys to integral, bool, or string.","Add a design-time reflection check over @ProtoMessage fields.","Flatten composite-key maps into a list of entry messages."],"tags":["protogen","protobuf","type-mapping","codegen"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}