Grasscutters/Grasscutter · error · IOException
Invalid Position definition -
Error message
Invalid Position definition -
What it means
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.
Source
Thrown at src/main/java/emu/grasscutter/utils/JsonAdapters.java:142
}
case BEGIN_OBJECT -> { // "pos": {"x": x, "y": y, "z": z}
float x = 0f;
float y = 0f;
float z = 0f;
reader.beginObject();
for (var next = reader.peek(); next != JsonToken.END_OBJECT; next = reader.peek()) {
val name = reader.nextName();
switch (name) {
case "x", "X", "_x" -> x = (float) reader.nextDouble();
case "y", "Y", "_y" -> y = (float) reader.nextDouble();
case "z", "Z", "_z" -> z = (float) reader.nextDouble();
default -> throw new IOException("Invalid field in Position definition - " + name);
}
}
reader.endObject();
return new Position(x, y, z);
}
default -> throw new IOException("Invalid Position definition - " + reader.peek().name());
}
}
@Override
public void write(JsonWriter writer, Position i) throws IOException {
writer.beginArray();
writer.value(i.getX());
writer.value(i.getY());
writer.value(i.getZ());
writer.endArray();
}
}
class EnumTypeAdapterFactory implements TypeAdapterFactory {
@SuppressWarnings("unchecked")
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
Class<T> enumClass = (Class<T>) type.getRawType();
if (!enumClass.isEnum()) return null;View on GitHub (pinned to f373827a83)
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
Example fix
// before "pos": "100.5, 200, 300.25" // after "pos": [100.5, 200, 300.25]
Defensive patterns
Strategy: type-guard
Validate before calling
boolean isWellFormedPositionValue(com.google.gson.JsonElement el) {
return el != null && (el.isJsonArray()
|| (el.isJsonObject() && el.getAsJsonObject().keySet().stream()
.allMatch(k -> k.matches("[xyzXYZ]|_[xyz]"))));
} Type guard
boolean isPositionLike(com.google.gson.JsonElement el) {
return el != null && (el.isJsonArray() && el.getAsJsonArray().size() == 3 || el.isJsonObject());
} Try / catch
try {
Position p = gson.fromJson(el, Position.class);
} catch (IOException e) {
logger.warn("Skipping malformed Position (token {})", e.getMessage());
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid DynamicFloat definition -
- Invalid IntList definition -
- Invalid GridPosition definition -
- Invalid field in Position definition -
- Invalid Enum definition -
AI-assisted analysis of Grasscutters/Grasscutter@f373827a83 (2026-09-03).
Data as JSON: /api/errors/e83bec0532c98aba.
Report an issue: GitHub.