Skip to content

fix(config): config mutations discard unknown JSON fields #964

Description

@PierrunoYT

Version / branch / commit

Audited on main at 903e3d13 (2026-08-23).

Problem

Most config mutators load JSON into the typed config struct and writeConfigFile rewrites the complete document with json.MarshalIndent. Fields unknown to the current binary are not represented by the struct and disappear on the next write.

Reproduction

Start with a valid config containing an additional field:

{
  "theme": "default",
  "futureSetting": {"a": 1}
}

Run a normal mutation such as SetTheme. The resulting file no longer contains futureSetting.

Expected behavior

Config writes preserve unknown fields so a current or older Zero binary does not destroy settings written by a newer version or extension.

Actual behavior

Any mutator that routes through writeConfigFile silently removes every unmodelled top-level field.

Relevant code

  • internal/config/writer.go:767-773
  • internal/config/unknownfields.go:14-22
  • internal/config/writer.go:596-621 (SetPet already uses a surgical raw-JSON update to avoid this class)

Suggested fix

Preserve extra top-level members as map[string]json.RawMessage through custom marshal/unmarshal logic, or generalize the raw-JSON mutation approach. Add a regression test proving an unknown object survives a representative config mutation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    issue-approvedReviewed and approved by the core team; community PRs may implement this issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions