Skip to content
Petrus Pradella edited this page Jun 28, 2026 · 6 revisions

FAQ & Gotchas

My comments disappeared after a save!

You probably saved with the JSON codec, whose comment fidelity is NONE — JSON has no comment syntax, so comments are accepted in memory but not emitted. Use YAML, TOML or JSONC if you need comments on disk. See Codecs & Formats.

A hand-edit to the file got overwritten

Outside a watcher, a Config lives in memory and save() never reads the file first — it dumps memory. Call reload() (or re-open()) before saving if you want a manual edit to survive. See Lifecycle, Reload & Watching.

TOML lost my null value

TOML has no null type. The TomlCodec omits a null-valued key on write, so it reads back as absent (the typed getter returns its default). If you need an explicit null on disk, use YAML, JSON or JSONC.

A huge integer came back as a string in TOML

The TOML reader mis-parses integers beyond the 64-bit range (and some near it). To keep the value intact, the TomlCodec writes such an integer as a quoted string — the numeric getters still read it as digits (getLong/getString both work), and on YAML/JSON it stays a number. This only affects values around 1e18 and larger.

Binding zeroed my field instead of keeping its default

It won't — lenient bind (the default) keeps the field's real default: the bad node is removed from a working copy of the tree and the bind is retried. Check binder.lastLoadIssues() to see what was skipped, or use STRICT to fail fast. See Entity Binding.

A key the user added by hand disappeared after a binding write

It shouldn't — a binding save merges: the tree wins and unknown keys survive. If you explicitly set ObsoletePolicy.REMOVE, that strips keys the schema no longer declares — that's opt-in and destructive. The default is PRESERVE.

How do I keep an obsolete key but mark it deprecated?

Bind with ObsoletePolicy.COMMENT_OUT — it keeps the key (the data survives, as with PRESERVE) but stamps an authoritative deprecation block comment on it, overwriting any stale comment it carried.

BindOptions opts = BindOptions.defaults()
        .withObsoletePolicy(BindOptions.ObsoletePolicy.COMMENT_OUT);

LOSSLESS codecs only. On a codec that can't round-trip a comment losslessly (JSON = NONE, JSONC = LOSSY) it degrades to PRESERVE: the key is kept, but no marker is written.

@Section on a nested POJO field didn't move

It should — @Section relocates a field of a nested POJO too, with the path taken relative to that POJO's own location. The one unsupported spot is a @Section field inside a List/Map element (a collection element has no stable path). A sectioned type also honors ObsoletePolicy.REMOVE like any other. See Annotations.

Which getter for a value stored as a quoted number?

Any numeric getter — they tolerate a number stored as a string: getLong("1700000000000"), getInt("25565"), getDouble("3.14") all parse. An empty string reads as the default.

getInt returned the default on a present-but-null key

That's the trichotomy: an explicit null is present (contains is true) but a typed getter flattens it to the default. Use getValue/getNode to tell a real value from null. See The Dynamic API.

Exotic YAML comments got mangled

The YAML comment parser is line-based and covers common block-style YAML. A # inside a |/> block scalar, anchors/merge-keys, explicit ? : keys, or multi-line flow can mis-attach a comment. The data is unaffected; only the comment overlay for those exotic shapes is best-effort.

Does Config.open guess the file format?

No — it never sniffs content. The single-arg overloads derive the codec from the file-name extension via CodecRegistry.defaults().forFile(...) and fail fast: a missing or unregistered extension throws a CodecException. Pass a codec explicitly to override or to use an unconventional name:

Config c = Config.open("settings.yml");                  // codec from ".yml"
Config c = Config.open(Paths.get("settings.cfg"), new YamlCodec()); // explicit

See Lifecycle, Reload & Watching.

Do I need to shade Jackson?

Not in the library — EveryConfig ships thin. A Bukkit/Spigot plugin that bundles it should relocate com.fasterxml.jackson and org.yaml.snakeyaml in its own shade step. See Installation.

Clone this wiki locally