Skip to content

config: Int/Bool getters swallow present-but-empty keys #1111

Description

@gaborage

Config.Int, Config.Int64, Config.Float64, and Config.Bool (config/getters.go) return the caller's default — or the type's zero when no default is passed — for a key that is present but empty. So CUSTOM_BATCHSIZE= plus cfg.Int("custom.batchsize") yields a silent 0, which is the same silent-zero this repo just closed at the decode layer in ADR-074.

The information needed to do better already exists one layer down and is thrown away: rawValue reports that the key exists, and toInt64 / toBool (config/converters.go) return errEmptyString for the empty case — the getter discards that error and falls back. So the converters layer already distinguishes "absent, use the default" from "present but unusable"; only the public getters collapse the two.

Why it matters

The framework now answers this input three different ways depending on which seam a consumer reads through:

seam FOO= for a numeric key
config.Load into framework structs fails startup naming the key (ADR-074)
Config.Unmarshal into a consumer struct fails, same rule
Config.RequiredInt returns an error
Config.InjectInto returns an error
Config.Int / Bool / Int64 / Float64 silently returns the default

The last row is the odd one out, and it is a documented public accessor — the seam a consumer reaches for when they do not want a struct.

Suggested shape

Have the getters separate absence from a present-but-unparseable value. Options worth weighing: return the zero value plus a logged WARN naming the key (cheapest, still silent to code), or add error-returning siblings and leave the current ones as the lenient path, or make them fail loudly and treat it as a behaviour change with an ADR + migrations atom. The choice depends on how much of the consumer surface is expected to keep the lenient reading; the current state is not a choice, it is an oversight inherited from before the delivered-empty rule existed.

Related: #1110 (the *bool half of the same class at the decode layer).

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/configAffects the config packagekind/tech-debtCleanup or maintenanceneeds-triageAwaiting maintainer triage

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions