Skip to content

config: tenant-tree errors use four different Field spellings #1113

Description

@gaborage

ADR-076 made a database section's normalization errors address themselves — ConfigError.Field reads databases.reporting.host or multitenant.tenants.acme.database.host instead of the root spelling. It deliberately stopped at the startup door. The result is a config package where a consumer can address some section failures and not others, and the split does not follow any line a consumer can see.

Where the spelling still doesn't match

The runtime door. database/manager.go (pool defaults for a dynamically-resolved tenant) and tools/migration/internal/commands/dbtls.go both hold the tenant key and both attach it by wrapping, leaving Field root-spelled. So the same tenant reports two different fields depending on how it was declared:

tenant declared Field
statically, in multitenant.tenants.acme.database multitenant.tenants.acme.database.tls
dynamically, via DBConfigProvider database.tls (key only in the message)

C60.16 tells consumers to route per-tenant failures with strings.HasPrefix(cfgErr.Field, "multitenant.tenants."). That advice works for static tenants and silently never fires for dynamic ones — the worst shape for a routing rule.

The rest of the tenant tree. Three more spellings for sibling failures of the same tenant:

  • tenant cache: wrapped as tenant <id> cache: …, Field left cache.*
  • checkTenantMessagingConsistency: Field: "multitenant.tenants messaging" — a space, not a path
  • NewMultiTenantError: Field: "tenant 'acme' database"

So Field is a koanf path for one failure class and prose for its neighbours.

Why it wasn't fixed in ADR-076

The connect door genuinely has no section — that is ADR-050's asymmetry, and #1025's brief explicitly excluded it. But the callers of the connect door do have the key, which is why this is worth deciding rather than assuming.

ADR-076's "Alternatives considered" names the shape that would dissolve this: give normalizeDatabaseValues the section (or a field prefix) so its errors are born addressed — one parameter at one seam, no prefix surgery, and Action gets built from the right head too (see the Action half in the companion issue). That refactor is the natural home for fixing the runtime door as well.

Suggested scope

  1. Decide whether Field is a koanf path always, or prose sometimes — then make the tenant tree consistent with that answer.
  2. If it is a path always, qualify at the two runtime-door call sites that already hold the key, and update C60.16's routing advice.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/configAffects the config packagekind/tech-debtCleanup or maintenanceready-for-agentFully specified, ready for an AFK agent

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions