Files
ServerKit/backend
Juan DenisandClaude Opus 5 dcb8810635 fix(errors): attribute a frontend crash report to the logged-in user
reportClientError sent no Authorization header, so every source='frontend' row
was anonymous no matter who was signed in -- which made ErrorLog.user_id,
to_dict()['username'] and the "User #N" row in pages/Errors.jsx dead end to
end, and the route's own docstring ("a valid JWT attaches user_id") false.

Attaching the header by hand does not violate the deliberate design here: the
comment forbids this.request() -- its 401 handling, refresh loop and throwing
-- not a header. The raw fetch and the swallow-everything contract are intact,
and Content-Type already made this a non-simple CORS request, so no new
preflight is added.

The review's stated rationale was wrong and the corrected version is in the
comment: verify_jwt_in_request(optional=True) tolerates a MISSING token only.
In Flask-JWT-Extended 4.6.0 it catches NoAuthorizationError alone, so an
expired token raises ExpiredSignatureError and garbage raises DecodeError. A
stale token is harmless here only because the route wraps that call in
try/except and falls back to an anonymous report -- tightening that except
would turn every expired session's crash report into a 500.

Three backend tests pin the contract the header relies on: valid token
attributes the row, no token stays anonymous, junk token stays anonymous
rather than 500ing. The frontend side that sends it is unproven -- the panel
has no test runner for pages.

Known ceiling: dedup bumps count on an existing unresolved row without
backfilling user_id, so attribution is first-writer-wins per fingerprint.

Reported by Copilot on the error-tracker PR.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 01:58:04 -04:00
..