Improve GraphQL Client Initialization Error Handling and Developer Feedback#4361
Improve GraphQL Client Initialization Error Handling and Developer Feedback#4361Saurabh-2607 wants to merge 7 commits intoOWASP:mainfrom
Conversation
Summary by CodeRabbit
WalkthroughStop constructing an AppError when Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
1 issue found across 2 files
Confidence score: 3/5
- There is a concrete medium-risk behavior in
frontend/src/wrappers/provider.tsx: the GraphQL endpoint probe skips the CSRF header, which can trigger backendcsrf_protect403 responses. - This can create a user-visible false negative where the endpoint is marked unreachable even though Apollo requests (with
X-CSRFToken) would succeed, so merge risk is moderate rather than low. - Pay close attention to
frontend/src/wrappers/provider.tsx- endpoint health checks may be incorrectly failing due to missing CSRF header handling.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="frontend/src/wrappers/provider.tsx">
<violation number="1" location="frontend/src/wrappers/provider.tsx:44">
P2: GraphQL endpoint probe omits CSRF header while the backend enforces csrf_protect, so the health check can return 403 and falsely mark the endpoint as unreachable even though Apollo (which adds X-CSRFToken) would work.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@frontend/src/utils/helpers/apolloClient.ts`:
- Around line 8-12: The code currently creates an AppError and calls
handleAppError() in apolloClient setup which causes a duplicate toast because
provider.tsx already shows a toast when apolloClient is null; remove the
handleAppError() call in this block (keep creating the AppError if you need it
for logging or throwing) and instead return null (or rethrow the AppError) so
the toast is emitted only once by frontend/src/wrappers/provider.tsx when
apolloClient is null; update references to AppError, handleAppError, and the
apolloClient initialization accordingly.
In `@frontend/src/wrappers/provider.tsx`:
- Around line 28-29: The GraphQL subtree mounts too early because
isGraphQLEndpointUnreachable defaults to false; add a reachability state (e.g.,
graphQLReachability: 'pending' | 'reachable' | 'unreachable' using
React.useState) and update it inside the existing effect that checks the
endpoint (replace setIsGraphQLEndpointUnreachable calls with setting 'reachable'
or 'unreachable' and set 'pending' initially); then gate mounting of
ApolloProvider, AppInitializer and children (the block currently rendered when
isGraphQLEndpointUnreachable is false) so it only renders when
graphQLReachability === 'reachable' (render a fallback UI for 'pending' and
'unreachable'); keep lastToastMessageRef logic intact for toasts but prevent
useDjangoSession / GraphQL hooks from mounting until reachability is confirmed.
- Around line 39-49: The reachability probe in verifyGraphQLEndpoint sends a
bare POST (using graphqlUrl) but does not include the same headers used by the
real client (notably X-CSRFToken), so it can give false negatives; update
verifyGraphQLEndpoint to build its request the same way as the real client (the
logic around X-CSRFToken in frontend/src/utils/helpers/apolloClient.ts) — e.g.
obtain the CSRF token the same way and add the X-CSRFToken header, keep
Content-Type, credentials: 'include', method: 'POST', and signal:
abortController.signal so the probe matches the actual GraphQL request shape
used by the app.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: eefc365a-c206-4a88-b136-d1036eba360a
📒 Files selected for processing (2)
frontend/src/utils/helpers/apolloClient.tsfrontend/src/wrappers/provider.tsx
There was a problem hiding this comment.
♻️ Duplicate comments (1)
frontend/src/wrappers/provider.tsx (1)
29-29:⚠️ Potential issue | 🟠 MajorRace condition: ApolloProvider mounts before reachability check completes.
The issue from the previous review remains:
isGraphQLEndpointUnreachabledefaults tofalse, and the conditional at lines 108-113 only checksapolloClientexistence—not the reachability state. This meansApolloProviderandAppInitializermount immediately on the first render, before theuseEffectat lines 32-73 can determine if the endpoint is reachable.useDjangoSession()will then kick off auth-sync mutations during the brief window before a failure is detected.Consider tracking a tri-state (e.g.,
'pending' | 'reachable' | 'unreachable') and only rendering the GraphQL subtree when reachability is confirmed.,
Also applies to: 108-113
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/wrappers/provider.tsx` at line 29, The current boolean state isGraphQLEndpointUnreachable causes ApolloProvider and AppInitializer to mount before the reachability check finishes; change this to a tri-state (e.g., const [graphQLEndpointStatus, setGraphQLEndpointStatus] = React.useState<'pending'|'reachable'|'unreachable'>('pending')), update that status inside the existing reachability useEffect (set to 'reachable' on success, 'unreachable' on failure), and alter the render logic so ApolloProvider and the subtree that calls useDjangoSession only render when graphQLEndpointStatus === 'reachable' (show an appropriate fallback UI for 'pending' and 'unreachable'); ensure you update references to isGraphQLEndpointUnreachable and the conditional that controls mounting of ApolloProvider/AppInitializer.
🧹 Nitpick comments (2)
frontend/src/wrappers/provider.tsx (2)
47-50: Minor inconsistency: CSRF token fallback differs from apolloClient.ts.The main Apollo client setup (in
apolloClient.tslines 21-25) usescsrfToken || ''as a fallback. For consistency and defensive coding, apply the same pattern here:headers: { 'Content-Type': 'application/json', - 'X-CSRFToken': csrfToken, + 'X-CSRFToken': csrfToken || '', },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/wrappers/provider.tsx` around lines 47 - 50, The headers object in provider.tsx sets 'X-CSRFToken' to csrfToken directly which is inconsistent with apolloClient.ts; update the 'X-CSRFToken' assignment in the headers (the object containing 'Content-Type' and 'X-CSRFToken') to use a defensive fallback like csrfToken || '' so it matches the apolloClient.ts pattern and avoids passing undefined.
108-113: Consider providing fallback UI when GraphQL is unavailable.When
apolloClientisnull, renderingnullleaves users on a blank page with only a toast notification. While this may be acceptable since the app can't function without GraphQL, consider rendering a minimal fallback (e.g., a centered error message or skeleton) to improve UX during configuration issues—especially for new contributors during local setup.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/wrappers/provider.tsx` around lines 108 - 113, When apolloClient is null the component currently returns null; add a minimal fallback UI so users don't see a blank page: create a small presentational component (e.g., GraphQLUnavailable or GraphQLFallback) and render it in place of the null branch where apolloClient is checked, keeping the existing ApolloProvider usage for the truthy branch; ensure the fallback includes a concise centered message (and optional retry/config instructions or a link to setup docs) and reference the existing symbols apolloClient, ApolloProvider, AppInitializer, and children so reviewers can find and replace the null return with the new fallback component.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@frontend/src/wrappers/provider.tsx`:
- Line 29: The current boolean state isGraphQLEndpointUnreachable causes
ApolloProvider and AppInitializer to mount before the reachability check
finishes; change this to a tri-state (e.g., const [graphQLEndpointStatus,
setGraphQLEndpointStatus] =
React.useState<'pending'|'reachable'|'unreachable'>('pending')), update that
status inside the existing reachability useEffect (set to 'reachable' on
success, 'unreachable' on failure), and alter the render logic so ApolloProvider
and the subtree that calls useDjangoSession only render when
graphQLEndpointStatus === 'reachable' (show an appropriate fallback UI for
'pending' and 'unreachable'); ensure you update references to
isGraphQLEndpointUnreachable and the conditional that controls mounting of
ApolloProvider/AppInitializer.
---
Nitpick comments:
In `@frontend/src/wrappers/provider.tsx`:
- Around line 47-50: The headers object in provider.tsx sets 'X-CSRFToken' to
csrfToken directly which is inconsistent with apolloClient.ts; update the
'X-CSRFToken' assignment in the headers (the object containing 'Content-Type'
and 'X-CSRFToken') to use a defensive fallback like csrfToken || '' so it
matches the apolloClient.ts pattern and avoids passing undefined.
- Around line 108-113: When apolloClient is null the component currently returns
null; add a minimal fallback UI so users don't see a blank page: create a small
presentational component (e.g., GraphQLUnavailable or GraphQLFallback) and
render it in place of the null branch where apolloClient is checked, keeping the
existing ApolloProvider usage for the truthy branch; ensure the fallback
includes a concise centered message (and optional retry/config instructions or a
link to setup docs) and reference the existing symbols apolloClient,
ApolloProvider, AppInitializer, and children so reviewers can find and replace
the null return with the new fallback component.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 804da8b8-6b4b-4166-a4da-56450a1202c9
📒 Files selected for processing (1)
frontend/src/wrappers/provider.tsx
a6c0b1d
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="frontend/src/wrappers/provider.tsx">
<violation number="1" location="frontend/src/wrappers/provider.tsx:113">
P2: Hardcoded inline unreachable text bypasses environment-aware error handling and can mislabel non-reachability failures.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
🧹 Nitpick comments (3)
frontend/src/wrappers/provider.tsx (3)
48-51: Add null coalescer for consistency with apolloClient.ts.The Apollo client setup in
apolloClient.tsusescsrfToken || ''as a defensive fallback (line 24). For consistency and defensive coding, apply the same pattern here.🔧 Suggested fix
headers: { 'Content-Type': 'application/json', - 'X-CSRFToken': csrfToken, + 'X-CSRFToken': csrfToken || '', },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/wrappers/provider.tsx` around lines 48 - 51, Update the headers construction in the provider setup to defensively coalesce the CSRF token like apolloClient.ts does; replace the direct use of csrfToken in the 'X-CSRFToken' header with a null-coalesced value (e.g., csrfToken || '') so the 'headers' object in provider.tsx always supplies a string for 'X-CSRFToken' and matches the behavior in apolloClient.ts.
77-85: Refactor nested ternaries for readability.SonarCloud correctly flagged the deeply nested ternaries. Extract this logic into a helper function with early returns for better maintainability.
♻️ Suggested refactor
+ const getGraphQLErrorMessage = (): string | null => { + if (!apolloClient) { + return isProduction + ? 'Something went wrong' + : 'GraphQL client setup required. Ensure backend is running and GraphQL environment variables are configured.' + } + if (graphQLReachability === 'unreachable') { + return isProduction + ? 'Something went wrong' + : 'GraphQL endpoint is unreachable. Ensure the backend service is running and NEXT_PUBLIC_GRAPHQL_URL is correct.' + } + return null + } + - const graphQLErrorMessage = !apolloClient - ? isProduction - ? 'Something went wrong' - : 'GraphQL client setup required. Ensure backend is running and GraphQL environment variables are configured.' - : graphQLReachability === 'unreachable' - ? isProduction - ? 'Something went wrong' - : 'GraphQL endpoint is unreachable. Ensure the backend service is running and NEXT_PUBLIC_GRAPHQL_URL is correct.' - : null + const graphQLErrorMessage = getGraphQLErrorMessage()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/wrappers/provider.tsx` around lines 77 - 85, Extract the nested ternary into a descriptive helper function (e.g., getGraphQLErrorMessage(apolloClient, graphQLReachability, isProduction)) that uses early returns to compute the message: first return the generic production/dev message when apolloClient is falsy, then handle the 'unreachable' graphQLReachability case with production/dev variants, and finally return null as the default; replace the inline ternary in provider.tsx (the graphQLErrorMessage const) with a call to this helper to improve readability and maintainability.
113-117: Consider showing the detailed error message inline in development.The inline UI always displays "GraphQL endpoint is unreachable." regardless of whether the issue is a missing client configuration or an unreachable endpoint. The toast shows the accurate
graphQLErrorMessage, but developers might miss it. Showing the detailed message inline would improve the debugging experience.💡 Suggested improvement
{graphQLReachability === 'unreachable' && ( <div style={{ padding: 32, textAlign: 'center', color: 'red' }}> - GraphQL endpoint is unreachable. + {graphQLErrorMessage || 'GraphQL endpoint is unreachable.'} </div> )}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/wrappers/provider.tsx` around lines 113 - 117, When graphQLReachability === 'unreachable' update the rendered JSX to include the detailed graphQLErrorMessage (falling back to the generic "GraphQL endpoint is unreachable.") and only display the full error inline in development by checking process.env.NODE_ENV === 'development'; locate the unreachable branch in provider.tsx where graphQLReachability is checked and replace the static message with a conditional that renders graphQLErrorMessage (or the fallback) when in dev while keeping the simple message in production.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@frontend/src/wrappers/provider.tsx`:
- Around line 48-51: Update the headers construction in the provider setup to
defensively coalesce the CSRF token like apolloClient.ts does; replace the
direct use of csrfToken in the 'X-CSRFToken' header with a null-coalesced value
(e.g., csrfToken || '') so the 'headers' object in provider.tsx always supplies
a string for 'X-CSRFToken' and matches the behavior in apolloClient.ts.
- Around line 77-85: Extract the nested ternary into a descriptive helper
function (e.g., getGraphQLErrorMessage(apolloClient, graphQLReachability,
isProduction)) that uses early returns to compute the message: first return the
generic production/dev message when apolloClient is falsy, then handle the
'unreachable' graphQLReachability case with production/dev variants, and finally
return null as the default; replace the inline ternary in provider.tsx (the
graphQLErrorMessage const) with a call to this helper to improve readability and
maintainability.
- Around line 113-117: When graphQLReachability === 'unreachable' update the
rendered JSX to include the detailed graphQLErrorMessage (falling back to the
generic "GraphQL endpoint is unreachable.") and only display the full error
inline in development by checking process.env.NODE_ENV === 'development'; locate
the unreachable branch in provider.tsx where graphQLReachability is checked and
replace the static message with a conditional that renders graphQLErrorMessage
(or the fallback) when in dev while keeping the simple message in production.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 4f41cb37-41ee-43d5-93bd-6bf7d932b13e
📒 Files selected for processing (2)
frontend/src/utils/helpers/apolloClient.tsfrontend/src/wrappers/provider.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/src/utils/helpers/apolloClient.ts
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@frontend/src/wrappers/provider.tsx`:
- Around line 120-124: Replace the hard-coded verbose message in the unreachable
render branch so production doesn't leak implementation details: when rendering
the div for graphQLReachability === 'unreachable' use the existing
graphQLErrorMessage value (the same string used for the toast) instead of
"GraphQL endpoint is unreachable.", so the UI shows the generic message in
production but still surfaces the detailed message in non-production; update the
component that references graphQLReachability to render graphQLErrorMessage and
ensure graphQLErrorMessage is defined/available in that scope (same symbol used
in the toast logic).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: eb244184-6ee6-4a8d-bcdf-5ec2d1883633
📒 Files selected for processing (1)
frontend/src/wrappers/provider.tsx



Proposed change
Resolves #4308
This PR improves error handling and developer feedback when the GraphQL client fails to initialize during the local setup of the OWASP Nest frontend.
Previously, the application displayed a generic message:
"Configuration Error: GraphQL Client failed to initialize"
This message did not clearly explain the possible causes, which could confuse new contributors during onboarding—especially when the backend service was not running or required environment variables were missing.
This PR enhances the developer experience by providing clearer guidance and more user-friendly feedback when configuration issues occur.
Changes Made
1. Improved Error Messaging (
apolloClient.ts)NEXT_PUBLIC_GRAPHQL_URLenvironment variable and ensure the backend service is running.2. Better User Feedback (
provider.tsx)3. Added Test Coverage (
provider.test.tsx)Added tests to verify that:
Messages and When They Appear
1. Missing GraphQL Configuration
NEXT_PUBLIC_GRAPHQL_URLis not set.2. Backend Not Reachable
3. Generic Production Notification
Why This Helps
These improvements make the setup process clearer and more developer-friendly by:
Checklist
make check-testlocally: all warnings addressed, tests passed