HMCL-dev/HMCL · error · JsonParseException

code is null

Error message

code is null

What it means

TerracottaState.State.validate enforces that the required 'code' member is present after JSON deserialization; a missing code means the state object is incomplete and cannot be used, so JsonParseException is thrown.

Solutions

  1. Add the required 'code' field to the state JSON
  2. Regenerate the terracotta state through the normal flow instead of editing the file manually
  3. Restore the file from backup if it was truncated
  4. Catch JsonParseException at load and re-initialize the terracotta state

Example fix

// before
{"profiles":[...]}
// after
{"code":"AUTH-CODE","profiles":[...]}
Defensive patterns

Strategy: type-guard

Validate before calling

if (parsedState.get("code") == null || parsedState.get("code").isJsonNull()) { throw new IllegalArgumentException("state.code required"); }

Type guard

static boolean hasNonNull(JsonObject o, String key) { return o.has(key) && !o.get(key).isJsonNull(); }

Try / catch

try { state.validate(); } catch (JsonParseException e) { /* re-run terracotta setup to regenerate state */ }

Prevention

When it happens

Trigger: Deserializing a terracotta state JSON that omits the code field — truncated file, older schema, or hand-edited config.

Common situations: Hand-editing the terracotta state file; version/schema drift dropping the code field; partial writes.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10). Data as JSON: /api/errors/1f6b7616ccf19c78. Report an issue: GitHub.

Appendix: source

Thrown at HMCL/src/main/java/org/jackhuang/hmcl/terracotta/TerracottaState.java:191

        private final String code;

        @SerializedName("profile_index")
        private final int profileIndex;

        @SerializedName("profiles")
        private final List<TerracottaProfile> profiles;

        HostOK(int port, int index, String state, String code, int profileIndex, List<TerracottaProfile> profiles) {
            super(port, index, state);
            this.code = code;
            this.profileIndex = profileIndex;
            this.profiles = profiles;
        }

        @Override
        public void validate() throws JsonParseException, TolerableValidationException {
            if (code == null) {
                throw new JsonParseException("code is null");
            }
            if (profiles == null) {
                throw new JsonParseException("profiles is null");
            }
        }

        public String getCode() {
            return code;
        }

        public List<TerracottaProfile> getProfiles() {
            return profiles;
        }

        @Override
        public boolean isForkOf(TerracottaState state) {
            return state instanceof HostOK hostOK && this.index - hostOK.index <= profileIndex;
        }

View on GitHub (pinned to 24702dc5a0)