{"record":{"id":"937dce0e14374347","repo":"google/gson","slug":"could-not-find-the-index-in-the-constructor-con","errorCode":null,"errorMessage":"Could not find the index in the constructor '${constructor}' for field with name '${fieldName}', unable to determine which argument in the constructor the field corresponds to. This is unexpected behavior, as we expect the RecordComponents to have the same names as the fields in the Java class, and that the order of the RecordComponents is the same as the order of the canonical constructor parameters.","messagePattern":"Could not find the index in the constructor '(.+?)' for field with name '(.+?)', unable to determine which argument in the constructor the field corresponds to\\. This is unexpected behavior, as we expect the RecordComponents to have the same names as the fields in the Java class, and that the order of the RecordComponents is the same as the order of the canonical constructor parameters\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java","lineNumber":631,"sourceCode":"      zeroes.put(long.class, 0L);\n      zeroes.put(float.class, 0F);\n      zeroes.put(double.class, 0D);\n      zeroes.put(char.class, '\\0');\n      zeroes.put(boolean.class, false);\n      return zeroes;\n    }\n\n    @Override\n    Object[] createAccumulator() {\n      return constructorArgsDefaults.clone();\n    }\n\n    @Override\n    void readField(Object[] accumulator, JsonReader in, BoundField field) throws IOException {\n      // Obtain the component index from the name of the field backing it\n      Integer componentIndex = componentIndices.get(field.fieldName);\n      if (componentIndex == null) {\n        throw new IllegalStateException(\n            \"Could not find the index in the constructor '\"\n                + ReflectionHelper.constructorToString(constructor)\n                + \"' for field with name '\"\n                + field.fieldName\n                + \"', unable to determine which argument in the constructor the field corresponds\"\n                + \" to. This is unexpected behavior, as we expect the RecordComponents to have the\"\n                + \" same names as the fields in the Java class, and that the order of the\"\n                + \" RecordComponents is the same as the order of the canonical constructor\"\n                + \" parameters.\");\n      }\n      field.readIntoArray(in, componentIndex, accumulator);\n    }\n\n    @Override\n    T finalize(Object[] accumulator) {\n      try {\n        return constructor.newInstance(accumulator);\n      } catch (IllegalAccessException e) {","sourceCodeStart":613,"sourceCodeEnd":649,"githubUrl":"https://github.com/google/gson/blob/310ac341f2f92a454b229bf21f70d2d18b2b6db7/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java#L613-L649","documentation":"While deserializing a record, Gson maps each field to a canonical constructor parameter by looking up the record component name. If a field name has no matching component, it cannot determine the constructor argument index and throws IllegalStateException. The message itself states this is unexpected because record component names should always match their fields.","triggerScenarios":"Bytecode manipulation (obfuscation, instrumentation, code weaving) renames record fields differently from their RecordComponents; a non-standard JVM or unusual record implementation breaks the expected name correspondence.","commonSituations":"ProGuard/R8 obfuscation rules applied to records without keep rules; AOP or agent instrumentation altering field metadata; a Gson-internal inconsistency under exotic conditions.","solutions":["Add ProGuard/R8 keep rules to preserve record component names (-keepattributes Record)","Register a custom TypeAdapter for the record to bypass Gson's reflective record handling","If no bytecode manipulation is involved, report the issue to the Gson project with a reproducer"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Verify field names match record component names at startup\npublic static void validateRecordFields(Class<?> recordType) {\n    var componentNames = Arrays.stream(recordType.getRecordComponents())\n        .map(RecordComponent::getName).collect(Collectors.toSet());\n    for (Field f : recordType.getDeclaredFields()) {\n        if (!Modifier.isStatic(f.getModifiers()) && !componentNames.contains(f.getName())) {\n            throw new IllegalStateException(\"Field \" + f.getName()\n                + \" has no matching record component in \" + recordType);\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    MyRecord r = gson.fromJson(json, MyRecord.class);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"Could not find the index\")) {\n        // likely bytecode manipulation; use a custom TypeAdapter\n    }\n}","preventionTips":["Add ProGuard/R8 keep rules (-keepattributes Record) to preserve record component names","Register custom TypeAdapters for records when using obfuscation or bytecode manipulation","Run an integration test that round-trips each record through Gson before shipping"],"tags":["record","deserialization","reflection","obfuscation"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}