fix(orgtoken): cast org_id to text in COALESCE to prevent 500

Symptom (prod tenant hongmingwang):
  GET /org/tokens → 500
  orgtoken list: orgtoken: list: pq: invalid input syntax for type uuid: ""

Postgres rejects COALESCE(uuid_col, '') because it can't cast the
empty string to UUID. Cast to ::text first so the COALESCE operates
on matching types. OrgID on the Go side is already string, so no
scan changes needed.

sqlmock doesn't exercise pq type coercion — it accepts any AddRow
value for any column — which is why the existing tests pass while
prod 500s. Real-Postgres integration coverage is the systemic fix
(tracked separately), but this PR unblocks the Settings → Org Tokens
page today.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hongming Wang 2026-04-22 17:18:56 -07:00
parent 2b603164de
commit 7d01f13500

View File

@ -142,8 +142,13 @@ func Validate(ctx context.Context, db *sql.DB, plaintext string) (id, prefix, or
// symptom of abuse or a bug — the hard cap prevents one runaway
// minting loop from O(N) pageloads in the admin UI.
func List(ctx context.Context, db *sql.DB) ([]Token, error) {
// org_id is a UUID column — COALESCE must cast to text first,
// otherwise Postgres rejects the empty-string literal with
// "pq: invalid input syntax for type uuid: ''". sqlmock doesn't
// exercise pq type coercion, so this bug only surfaces against
// a real Postgres (prod).
rows, err := db.QueryContext(ctx, `
SELECT id, prefix, COALESCE(name,''), COALESCE(org_id,''),
SELECT id, prefix, COALESCE(name,''), COALESCE(org_id::text,''),
COALESCE(created_by,''), created_at, last_used_at
FROM org_api_tokens
WHERE revoked_at IS NULL