Summary
GET /creator/user/whoami returns HTTP 500 for any user whose email address uses a reserved or special-use TLD (.test, .local, .invalid, …). The user can be created and can log in normally — only whoami fails, and it fails permanently for that account.
Reproduction
lamb login -s http://localhost:9099 -e admin@owi.com -p <admin-pass>
lamb user create someone@example.test "Some One" <password> -t creator # succeeds
lamb login -s http://localhost:9099 -e someone@example.test -p <password> # succeeds
lamb whoami # Error: API error (500)
The same user with a @example.com address works correctly. Reproduced on dev (2026-08-01) via lamb-cli; the endpoint is shared with the frontend, so any client is affected.
Root cause
The response model validates email as EmailStr, and email-validator rejects reserved TLDs. FastAPI raises ResponseValidationError after the handler has done its work, which surfaces as an unhandled 500:
fastapi.exceptions.ResponseValidationError: 1 validation errors:
{'type': 'value_error', 'loc': ('response', 'email'),
'msg': 'value is not a valid email address: The part after the @-sign is a
special-use or reserved name that cannot be used with email.',
'input': 'vk-check@lamb.test'}
The underlying defect is an asymmetry between the write path and the read path: user creation accepts an address that the read path cannot serialize. Any account created that way is left in a state where it exists, authenticates, and works for other endpoints, but cannot report its own identity.
Impact
- Test, staging, and CI environments routinely use
.test / .local addresses; every such account is broken on whoami, and the failure mode (500, no message) gives no clue why.
- The mismatch is silent at creation time — nothing warns that the address will break later.
Suggested fix
Make the two paths agree, in whichever direction the project prefers:
- Relax the response model (plain
str, or EmailStr with special-use domains permitted) so anything creatable is serializable; or
- Apply the same validation at user creation and reject the address up front with a clear message.
Option 1 is the smaller change and keeps test environments usable. Either way, a regression test should create a user with a reserved-TLD address and assert that whoami responds cleanly.
Provenance
Found by an automated black-box agent test run (organization-bootstrap module) and verified by hand. The agent originally attributed the failure to non-admin role, which was incorrect — a .com non-admin creator user returns 200 — the determining variable is the email domain.
Summary
GET /creator/user/whoamireturns HTTP 500 for any user whose email address uses a reserved or special-use TLD (.test,.local,.invalid, …). The user can be created and can log in normally — onlywhoamifails, and it fails permanently for that account.Reproduction
The same user with a
@example.comaddress works correctly. Reproduced ondev(2026-08-01) vialamb-cli; the endpoint is shared with the frontend, so any client is affected.Root cause
The response model validates
emailasEmailStr, andemail-validatorrejects reserved TLDs. FastAPI raisesResponseValidationErrorafter the handler has done its work, which surfaces as an unhandled 500:The underlying defect is an asymmetry between the write path and the read path: user creation accepts an address that the read path cannot serialize. Any account created that way is left in a state where it exists, authenticates, and works for other endpoints, but cannot report its own identity.
Impact
.test/.localaddresses; every such account is broken onwhoami, and the failure mode (500, no message) gives no clue why.Suggested fix
Make the two paths agree, in whichever direction the project prefers:
str, orEmailStrwith special-use domains permitted) so anything creatable is serializable; orOption 1 is the smaller change and keeps test environments usable. Either way, a regression test should create a user with a reserved-TLD address and assert that
whoamiresponds cleanly.Provenance
Found by an automated black-box agent test run (organization-bootstrap module) and verified by hand. The agent originally attributed the failure to non-admin role, which was incorrect — a
.comnon-admin creator user returns 200 — the determining variable is the email domain.