control: a store failure is a failure, not a usage error !204

merged merged by cmc on 2026-09-04 00:10 UTC · krz/gitbay:store-errors into main

Discussion

cmc

Fifty-seven sites reported any error from a store or helper call with ExitUsage, so a SQLite I/O failure was exit 2 over ssh and HTTP 400 over the API, and a not-found from the store was a usage error too.

Ctx.failErr maps store.ErrNotFound (wrapped or not) to exit 3, a database or I/O failure to exit 1 via store.IsInternal (a SQLite driver error, a path error, a closed transaction or connection, a cancelled context), and everything else, which is the caller's input or a state that refuses the change, to exit 2 as before. Every site was converted mechanically; the sentinels ErrExists, ErrDuplicateKey and ErrLastAdmin keep exit 2.

TestFailErrExitCodes and TestIsInternal. The exit-code-sensitive e2e tests (issues, MRs, repos, orgs, teams, releases, milestones, webhooks, tokens, admin, deploy keys, mirrors, import, labels, profiles, pages) pass.

Stacked on !203; no code dependency.

Closes #107

retargeted from json-first to main: !203 merged

2026-09-04 00:10 UTC