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

  1. Change the field value in the flagged JSON file to the string form, e.g. "(1, 2, 3)"
  2. If the source data provides [x,y,z], convert it to the parenthesized string before loading
  3. Re-acquire resources matching the version Grasscutter's adapter was written for
  4. 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

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


AI-assisted analysis of Grasscutters/Grasscutter@f373827a83 (2026-09-03). Data as JSON: /api/errors/ec2b73538aa14620. Report an issue: GitHub.