fix(calendar/google): structured error logging and user-friendly messages for OAuth failures - #262
Merged
Merged
Conversation
…messages for OAuth failures - Extract oauth-errors.ts with userMessageForTokenEndpointError and userMessageForCalendarApiError - Log full Google error body (status, error code, description) on token exchange failure - Map RFC 6749 error codes to actionable user messages; never surface raw 400/invalid_grant in UI - Warn on startup if GOOGLE_CALENDAR_CLIENT_SECRET is set (Desktop clients do not need it) - Validate Calendar scope after token exchange; throw friendly message if scope not granted - Apply same two-layer error pattern to Calendar API client (list/create/events/upsert/delete)
…on token 400 - Use vi.hoisted() for loggerMock to avoid TDZ with vi.mock() hoisting - Assert thrown message excludes raw '400' and 'invalid_grant' - Assert loggerMock.error called with status/error/errorDescription fields
h4yfans
added a commit
that referenced
this pull request
May 6, 2026
…nostic fix(calendar/google): structured error logging and user-friendly messages for OAuth failures
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Add a two-layer error architecture for the Google Calendar OAuth flow: verbose structured logs in the terminal (status, error code, description) while the UI receives clear, actionable messages derived from RFC 6749 error codes.
Why
The OAuth token exchange was silently returning status 400 with no diagnostic information — the error body was swallowed entirely. This made it impossible to know whether the failure was
invalid_client,invalid_grant,redirect_uri_mismatch, etc. Root cause turned out to be a misnamed env var (GOOGLE_CLIENT_SECRETvsGOOGLE_CALENDAR_CLIENT_SECRET), which was only discoverable after opening the error body.How
oauth-errors.ts(new): maps RFC 6749 error codes and Google API status codes to user-friendly string constants (RECONNECT_NEEDED,MISCONFIGURED,ACCESS_DENIED, etc.)oauth.ts:readOAuthErrorBody()helper reads + JSON-parses the response body safely;exchangeCodeForTokenslogs{status, error, errorDescription, redirectUri, clientIdSuffix}and throws a friendly message; startup warns ifGOOGLE_CALENDAR_CLIENT_SECRETis set (Desktop OAuth clients don't need it); scope validation after token exchange throwsCALENDAR_SCOPE_NOT_GRANTED_MESSAGEwith a log if Calendar scope was not grantedclient.ts:throwCalendarApiFailure(response, operation): Promise<never>applied to all 5 API paths;refreshAccessTokenInnerlogs + maps errors the same wayoauth.test.ts:vi.hoisted()for logger mock (avoids TDZ withvi.mock()hoisting); new test asserts message excludes raw400/invalid_grantandloggerMock.errorcaptures structured technical fieldsType
Test plan
oauth.test.ts— 400 error behavior + logger assertions){status, error, errorDescription}; UI shows "Your Google Calendar connection has expired. Please disconnect and connect again." instead of raw statusChecklist