{"record":{"id":"e83bec0532c98aba","repo":"Grasscutters/Grasscutter","slug":"invalid-position-definition","errorCode":null,"errorMessage":"Invalid Position definition - ","messagePattern":"Invalid Position definition - ","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/main/java/emu/grasscutter/utils/JsonAdapters.java","lineNumber":142,"sourceCode":"                }\n                case BEGIN_OBJECT -> { // \"pos\": {\"x\": x, \"y\": y, \"z\": z}\n                    float x = 0f;\n                    float y = 0f;\n                    float z = 0f;\n                    reader.beginObject();\n                    for (var next = reader.peek(); next != JsonToken.END_OBJECT; next = reader.peek()) {\n                        val name = reader.nextName();\n                        switch (name) {\n                            case \"x\", \"X\", \"_x\" -> x = (float) reader.nextDouble();\n                            case \"y\", \"Y\", \"_y\" -> y = (float) reader.nextDouble();\n                            case \"z\", \"Z\", \"_z\" -> z = (float) reader.nextDouble();\n                            default -> throw new IOException(\"Invalid field in Position definition - \" + name);\n                        }\n                    }\n                    reader.endObject();\n                    return new Position(x, y, z);\n                }\n                default -> throw new IOException(\"Invalid Position definition - \" + reader.peek().name());\n            }\n        }\n\n        @Override\n        public void write(JsonWriter writer, Position i) throws IOException {\n            writer.beginArray();\n            writer.value(i.getX());\n            writer.value(i.getY());\n            writer.value(i.getZ());\n            writer.endArray();\n        }\n    }\n\n    class EnumTypeAdapterFactory implements TypeAdapterFactory {\n        @SuppressWarnings(\"unchecked\")\n        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {\n            Class<T> enumClass = (Class<T>) type.getRawType();\n            if (!enumClass.isEnum()) return null;","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/Grasscutters/Grasscutter/blob/f373827a83d3e688fd3c6afb1e1c3759ca1d61c9/src/main/java/emu/grasscutter/utils/JsonAdapters.java#L124-L160","documentation":"The Position TypeAdapter dispatches on JsonReader.peek(): an array is the canonical form and an object is the key-based form; any other token (STRING, NUMBER, BOOLEAN, NULL, NAME, END_*) is rejected. This occurs when a Position value in JSON is not an array or object, e.g. a bare number, string, or null.","triggerScenarios":"Parsing JSON where a Position field holds a non-structural value: \"pos\": null, \"pos\": \"1,2,3\", \"pos\": 100, or malformed input where the reader is positioned at a NAME token due to earlier mis-parsing.","commonSituations":"Null coordinates in exported configs; positions serialized as delimited strings by other tools; truncated or corrupted JSON files leaving the reader at an unexpected token.","solutions":["Set the field to the canonical array form [x, y, z] in the JSON","Set the field to an object form {\"x\":..,\"y\":..,\"z\":..}","Replace null with a valid position or make the containing field optional/generic so the adapter is not invoked on null","Validate/repair the JSON file with a linter before loading"],"exampleFix":"// before\n\"pos\": \"100.5, 200, 300.25\"\n// after\n\"pos\": [100.5, 200, 300.25]","handlingStrategy":"type-guard","validationCode":"boolean isWellFormedPositionValue(com.google.gson.JsonElement el) {\n  return el != null && (el.isJsonArray()\n      || (el.isJsonObject() && el.getAsJsonObject().keySet().stream()\n          .allMatch(k -> k.matches(\"[xyzXYZ]|_[xyz]\"))));\n}","typeGuard":"boolean isPositionLike(com.google.gson.JsonElement el) {\n  return el != null && (el.isJsonArray() && el.getAsJsonArray().size() == 3 || el.isJsonObject());\n}","tryCatchPattern":"try {\n  Position p = gson.fromJson(el, Position.class);\n} catch (IOException e) {\n  logger.warn(\"Skipping malformed Position (token {})\", e.getMessage());\n}","preventionTips":["Never emit null, strings, or bare numbers for Position fields","Always serialize positions as [x,y,z] arrays","Validate JSON structure with a parser before handing it to Gson","Check for truncated files if many positions fail at once"],"tags":["json","gson","deserialization","grasscutter"],"backgroundTag":"invalid-json-structure","analyzedSha":"f373827a83d3e688fd3c6afb1e1c3759ca1d61c9","analyzedAt":"2026-09-03T22:43:49.407Z","contentChangedAt":"2026-09-03T22:43:49.407Z","schemaVersion":2},"datasetVersion":"2026-09-11T07:07:21.782Z"}