{"record":{"id":"4c8ed79ce5a8a2c9","repo":"OpenAPITools/openapi-generator","slug":"unreferenced-enum-hash","errorCode":null,"errorMessage":"Unreferenced enum {hash}","messagePattern":"Unreferenced enum (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/OCamlClientCodegen.java","lineNumber":932,"sourceCode":"    }\n\n    @Override\n    public String escapeUnsafeCharacters(String input) {\n        return input\n                .replace(\"*)\", \"*_)\")\n                .replace(\"(*\", \"(_*\")\n                .replace(\"\\\"\", \"''\");\n    }\n\n    @Override\n    public String toEnumName(CodegenProperty property) {\n        Set<String> hash = new TreeSet<>(property.get_enum());\n\n        if (enumUniqNames.containsKey(hash)) {\n            return enumUniqNames.get(hash);\n        }\n\n        throw new IllegalArgumentException(\"Unreferenced enum \" + hash);\n    }\n\n    @Override\n    public String toDefaultValue(Schema p) {\n        if (p.getDefault() != null) {\n            if (p.getEnum() != null) {\n                return ocamlizeEnumValue(p.getDefault().toString());\n            }\n            return p.getDefault().toString();\n        } else {\n            return null;\n        }\n    }\n\n    @Override\n    public void postProcessFile(File file, String fileType) {\n        super.postProcessFile(file, fileType);\n","sourceCodeStart":914,"sourceCodeEnd":950,"githubUrl":"https://github.com/OpenAPITools/openapi-generator/blob/fcec517be3cf5b7964296bcba25fbc97541484e7/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/OCamlClientCodegen.java#L914-L950","documentation":"The OCaml generator pre-registers every enum it knows about: collectEnumSchemas() walks components.schemas and each operation's parameters, then computeEnumUniqNames() assigns each distinct enum value-set an OCaml name, stored in enumUniqNames keyed by the set of values. Later, toEnumName() looks up property.get_enum() in that registry and throws 'Unreferenced enum' (OCamlClientCodegen.java:932) when the value-set was never registered — i.e. the enum lives somewhere collectEnumSchemas() does not walk.","triggerScenarios":"Generating with `-g ocaml` from a spec that declares an enum inline in a location the collector misses — e.g. inline in a response schema, a requestBody schema, or a nested inline object — so the model contains an enum value-set absent from enumUniqNames when toEnumName() runs.","commonSituations":"Specs that use inline enums instead of named component schemas; converting a spec from another generator workflow where inline enums were tolerated; adding response examples with inline enum constraints after the initial component-based design.","solutions":["Hoist the offending enum into components/schemas and reference it via $ref from the response/requestBody/property.","Or move the enum inline into an operation parameter schema, which the collector does walk.","Upgrade openapi-generator — enum collection coverage in the OCaml generator has been patched over time; if the shape is valid OpenAPI, file an issue with the spec."],"exampleFix":"# before (inline enum in a response)\npaths:\n  /status:\n    get:\n      responses:\n        '200':\n          content:\n            application/json:\n              schema:\n                type: string\n                enum: [ready, busy]\n# after (named component enum)\npaths:\n  /status:\n    get:\n      responses:\n        '200':\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Status'\ncomponents:\n  schemas:\n    Status:\n      type: string\n      enum: [ready, busy]","handlingStrategy":"validation","validationCode":"// ocaml: verify every enum in the spec is reachable from walked locations\n// (components.schemas and operation parameters); hoist inline response/requestBody enums.\nSet<Set<String>> declared = new HashSet<>();\nopenAPI.getComponents().getSchemas().values().forEach(s -> {\n  if (s.getEnum() != null) declared.add(new TreeSet<>(s.getEnum().stream().map(String::valueOf).toList()));\n});\n// walk responses/requestBodies for inline enums not in `declared` and report them\nfor (var path : openAPI.getPaths().values()) {\n  for (Operation op : path.readOperations().values()) {\n    if (op.getResponses() == null) continue;\n    for (ApiResponse r : op.getResponses().values()) {\n      if (r.getContent() == null) continue;\n      for (MediaType mt : r.getContent().values()) {\n        Schema<?> s = mt.getSchema();\n        if (s != null && s.getEnum() != null\n            && !declared.contains(new TreeSet<>(s.getEnum().stream().map(String::valueOf).toList()))) {\n          throw new IllegalArgumentException(\"Inline enum in response of \" + op.getOperationId()\n              + \" must be hoisted to components/schemas for the ocaml generator\");\n        }\n      }\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n    new DefaultGenerator().opts(clientOptInput).generate();\n} catch (IllegalArgumentException e) {\n    // message prints the unregistered enum value-set; find it in the spec and hoist to components\n    throw new BuildException(\"OCaml generation failed: \" + e.getMessage(), e);\n}","preventionTips":["Prefer named enums in components/schemas with $ref over inline enums throughout the spec.","Run a spectral-style rule forbidding inline enums in response/requestBody schemas when targeting -g ocaml.","Keep generator version current; enum collection coverage improves across releases."],"tags":["ocaml","enum","inline-schema","dollar-ref","openapi-spec","openapi-generator","spec-validation"],"backgroundTag":"unresolved-enum-reference","analyzedSha":"fcec517be3cf5b7964296bcba25fbc97541484e7","analyzedAt":"2026-08-22T11:13:11.613Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}