--- status: resolved opened: 2026-10-04 located-in: [mesh-catalog modules/photos] fixed-by: mesh-catalog#264 amended-design: --- # 232 — A consumer authenticates against a database its user does not live in, and one fault hid it behind another ## What was observed Fixing [issue 225](../225-a-provisioner-cannot-read-the-grant-secrets-since-its-code-left-the-container/00-report.md) on the control machine, 2026-10-04. With the grant secrets readable again the provisioner created both consumers' users at once, and one consumer still could not connect: ``` Authentication succeeded | user: mesh_novox_invoice | authDb: mesh_novox_invoice Authentication succeeded | user: mesh_novox_photos | authDb: mesh_novox_photos Authentication failed | user: mesh_novox_photos | authDb: admin UserNotFound: Could not find user "mesh_novox_photos" for db "admin" ``` The provider creates each consumer's user **in that consumer's own database**, which is what the first two lines are. `photos` asks for `admin`. Its sibling `invoicing`, against the same provider, asks for `${bound:mongodb-database:as}` — the name the mesh gave it — and works. The password was never the problem: the grant secret and the value in the consumer's environment hash identically. ## Why it matters beyond this instance **One fault wore the other's clothes.** While the provisioner could not read its secrets at all, *no* user existed, so `UserNotFound ... for db "admin"` was a true and complete account of issue 225. Fixing 225 is what made the wrong database visible — before that, every symptom pointed at the thing that was already broken, and a second fault behind it was indistinguishable. That is the general shape worth keeping: **a fault that explains the symptom is not evidence there is only one.** The check is to fix the first and look again, rather than to close both on one explanation. It also says something about the interface. Which database a consumer authenticates against is part of what `mongodb-database` means, and it is spelled out by hand in each consumer. Two consumers of one provider wrote two different answers, and only one was right; nothing compared them. That is the shape [issue 124](../124-a-consumer-cannot-be-told-what-its-provider-derived/00-report.md) records for a derived bucket, here for the authentication database — [ADR 0202](../../02-DECISIONS/0202-a-provider-declares-what-it-derives-for-each-consumer.md)'s mechanism is what would remove it, by letting the provider say it once. ## Resolved `photos` asks for `${bound:mongodb-database:as}`, as `invoicing` already did (mesh-catalog#264). **How it is checked:** the module is rebuilt and pushed, and `photos-server` connects — verified on the control machine rather than inferred from the manifest. ## What this leaves open Nothing compares two consumers' idea of one interface. The provider could serve the authentication database as a derived value under ADR 0202 and neither consumer would state it; that is a candidate for the next consumer of this interface, not a repair of this one.