Grasscutters/Grasscutter · error · IOException
Invalid GridPosition definition -
Error message
Invalid GridPosition definition -
What it means
The GridPosition adapter expects its JSON value to be a string of the form "(x, y, z)". If the peeked token is not a STRING (e.g. an array, object, number, or null), it throws this IOException naming the unexpected token. This guards the string-parsing logic that strips parentheses and splits on commas.
Source
Thrown at src/main/java/emu/grasscutter/utils/JsonAdapters.java:99
out.value(Utils.base64Encode(value));
}
@Override
public byte[] read(JsonReader in) throws IOException {
return Utils.base64Decode(in.nextString());
}
}
class GridPositionAdapter extends TypeAdapter<GridPosition> {
@Override
public void write(JsonWriter out, GridPosition value) throws IOException {
out.value("(" + value.getX() + ", " + value.getZ() + ", " + value.getWidth() + ")");
}
@Override
public GridPosition read(JsonReader in) throws IOException {
if (in.peek() != JsonToken.STRING)
throw new IOException("Invalid GridPosition definition - " + in.peek().name());
// GridPosition follows the format of: (x, y, z).
// Flatten to (x,y,z) for easier parsing.
var str = in.nextString().replace("(", "").replace(")", "").replace(" ", "");
var split = str.split(",");
if (split.length != 3)
throw new IOException("Invalid GridPosition definition - " + in.peek().name());
return new GridPosition(
Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2]));
}
}
class PositionAdapter extends TypeAdapter<Position> {
@Override
public Position read(JsonReader reader) throws IOException {
switch (reader.peek()) {View on GitHub (pinned to f373827a83)
Solutions
- Change the field value in the flagged JSON file to the string form, e.g. "(1, 2, 3)"
- If the source data provides [x,y,z], convert it to the parenthesized string before loading
- Re-acquire resources matching the version Grasscutter's adapter was written for
- Locate which file/field failed by reading the Gson path in the stack trace
Example fix
// before (resource JSON) "size": [1, 2, 3] // after "size": "(1, 2, 3)"
Defensive patterns
Strategy: validation
Validate before calling
// Check GridPosition fields are the expected "(x, y, z)" string before parsing
static boolean isValidGridPosition(com.google.gson.JsonElement e) {
return e != null && e.isJsonPrimitive() && e.getAsJsonPrimitive().isString()
&& e.getAsString().matches("\\s*\\(\\s*-?\\d+\\s*,\\s*-?\\d+\\s*,\\s*-?\\d+\\s*\\)\\s*");
} Type guard
static boolean isGridPositionString(com.google.gson.JsonElement el) {
if (el == null || !el.isJsonPrimitive() || !el.getAsJsonPrimitive().isString()) return false;
return el.getAsString().trim().matches("\\(-?\\d+,\\s*-?\\d+,\\s*-?\\d+\\)");
} Try / catch
try {
GridPosition p = gson.fromJson(json, GridPosition.class);
} catch (IOException | JsonParseException e) {
logger.error("Invalid GridPosition definition: {}", e.getMessage());
GridPosition p = new GridPosition(0, 0, 0); // neutral fallback
} Prevention
- Serialize GridPosition as the string "(x, y, z)", never as arrays or objects
- Do not convert coordinates to JSON arrays when re-dumping resources
- Validate position strings with a regex before loading
- Use one canonical resource source to avoid mixed-format files
When it happens
Trigger: A GridPosition field in a resource/config JSON is encoded as an array [x,y,z], a JSON object, a number, or null instead of the string "(x, y, z)" when deserialized by Gson.
Common situations: Resource dumps from a different game version where GridPosition fields changed representation, custom tooling that serializes positions as arrays, or hand-edited spawn/blocking-point data files.
Related errors
- Invalid DynamicFloat definition -
- Invalid IntList definition -
- Invalid field in Position definition -
- Invalid Position definition -
- Invalid Enum definition -
AI-assisted analysis of Grasscutters/Grasscutter@f373827a83 (2026-09-03).
Data as JSON: /api/errors/ec2b73538aa14620.
Report an issue: GitHub.