Skip to content

fix(web,api): tolerate null journey slices - #115

Merged
atulmgupta merged 4 commits into
mainfrom
fix/journeys-null-length
Sep 17, 2026
Merged

atulmgupta merged 4 commits into
mainfrom
fix/journeys-null-length

Conversation

@atulmgupta

Copy link
Copy Markdown
Contributor

Summary

/journeys crashed with Cannot read properties of null (reading ''length'') because a planned journey auto-opens the leave-now nudge and Go encoded Blockers(nil) as JSON null.

Changes

  • Return empty [] from Blockers when there is no checklist run
  • Guard journey arrays (plans, next_statuses, blockers, slots, evidence, trail, items) with safeArray in hooks and panels
  • Regression test: planned journey with null slices still renders

Test

  • go test ./internal/api/journey/
  • npx vitest run src/features/trips/components/JourneyPanel.test.tsx
  • cd web && npx tsc --noEmit
  • Reload /journeys after the web/API images update

Planned journeys crashed /journeys because Blockers(nil) JSON-encodes
as null and NudgePanel read blockers.length. Guard journey arrays and
return empty blockers as [].

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5b104204-65b7-4d04-90a4-e2d5897b8e2e
Copilot AI lite review requested due to automatic review settings September 17, 2026 17:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The changes directly address the nil-slice/null-array crash at both the API source and UI consumption points, and include a focused regression test for the reported failure mode.

Pull request overview

This PR fixes a /journeys frontend crash caused by Go encoding nil slices as JSON null (notably Blockers(nil)), and hardens the journeys UI + hooks against nullable slice fields so planned journeys still render.

Changes:

  • Backend: Blockers(nil) now returns an empty slice so JSON encodes [] instead of null.
  • Frontend: journey-related panels/tables and useJourney hooks normalize nullable arrays via safeArray to avoid .length/.map crashes.
  • Tests: adds a regression test ensuring JourneyPanel renders when detail/nudge/checklist payloads contain null slices.
File summaries
File Description
web/src/features/trips/components/StopScoreTable.tsx Normalizes evidence and stops to arrays before rendering.
web/src/features/trips/components/StopScorePanel.tsx Normalizes oracle sites + score result stops with safeArray.
web/src/features/trips/components/ReportPanel.tsx Prevents crashes when report.evidence is null.
web/src/features/trips/components/ReplanPanel.tsx Prevents crashes when assessment/result evidence/stops are null.
web/src/features/trips/components/NudgePanel.tsx Prevents crashes when blockers/evidence are null.
web/src/features/trips/components/LiveTripPanel.tsx Prevents crashes when trail/evidence are null.
web/src/features/trips/components/JourneyPanel.tsx Normalizes sessions, next_statuses, and plans to arrays before iterating/reading length.
web/src/features/trips/components/JourneyPanel.test.tsx Adds regression coverage for planned journeys with null slices.
web/src/features/trips/components/DeparturePanel.tsx Normalizes slots and evidence to arrays before rendering.
web/src/features/trips/components/ChecklistPanel.tsx Normalizes items to an array before mapping.
web/src/features/trips/components/ArrivalPanel.tsx Prevents crashes when arrival.evidence is null.
web/src/api/hooks/useJourney.ts Adds select normalizers to coerce nullable slice fields to [] at the hook boundary.
internal/api/journey/nudge.go Ensures Blockers(nil) produces JSON [] and updates comment accordingly.
internal/api/journey/nudge_test.go Updates unit test to assert Blockers(nil) is a non-nil empty slice.
Review details
  • Files reviewed: 14/14 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Copilot AI commented Sep 17, 2026

Copy link
Copy Markdown

One or more custom setup steps configured for this repository failed during this Copilot code review run:

Verify TypeScript build

Setup steps run before each review. If the review above is missing context, or no review was posted at all, the failing step above may be the cause. See the workflow run for failure details, fix your setup steps configuration, and re-request a review.

Note

You can configure setup steps for Copilot code review separately from Copilot cloud agent with a copilot-code-review.yml file. Read the docs for details.

CI Frontend failed on a flake: useLastDiagnostic used getQueryData (no observer),
so gcTime:0 tests could drop diagnosticKeys.last before waitFor saw the report.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5b104204-65b7-4d04-90a4-e2d5897b8e2e
Copilot AI review requested due to automatic review settings September 17, 2026 18:13

Copilot AI commented Sep 17, 2026

Copy link
Copy Markdown

One or more custom setup steps configured for this repository failed during this Copilot code review run:

Verify TypeScript build

Setup steps run before each review. If the review above is missing context, or no review was posted at all, the failing step above may be the cause. See the workflow run for failure details, fix your setup steps configuration, and re-request a review.

Note

You can configure setup steps for Copilot code review separately from Copilot cloud agent with a copilot-code-review.yml file. Read the docs for details.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The changes consistently address the confirmed null-slice crash across backend encoding, frontend normalization, and add a targeted regression test.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

web/src/features/trips/components/JourneyPanel.tsx:350

  • safeArray(detail.plans) is evaluated twice (length check + map), which can duplicate work and double-log warnings if the backend ever sends a non-array value. Consider computing it once and reusing it for both branches.
  • Files reviewed: 15/15 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

audit:query-signal requires cache-only useQuery to destructure and
reference { signal } even though queryFn never runs (enabled: false).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5b104204-65b7-4d04-90a4-e2d5897b8e2e
Copilot AI review requested due to automatic review settings September 17, 2026 18:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The changes consistently address the null-slice crash across the API and UI and include a targeted regression test; only a minor performance nit was noted.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

web/src/features/trips/components/JourneyPanel.tsx:113

  • safeArray() returns a new empty array ([]) each render when listQuery.data is null/undefined (see web/src/lib/safeArray.ts). Since sessions is used as a dependency in the useEffect below, this makes the effect run on every render while the list is empty/loading, causing unnecessary work and repeated setSelectedId(...) calls. Prefer depending on the raw query data and re-normalizing inside the effect so the dependency is referentially stable.
  • Files reviewed: 15/15 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI commented Sep 17, 2026

Copy link
Copy Markdown

One or more custom setup steps configured for this repository failed during this Copilot code review run:

Verify TypeScript build

Setup steps run before each review. If the review above is missing context, or no review was posted at all, the failing step above may be the cause. See the workflow run for failure details, fix your setup steps configuration, and re-request a review.

Note

You can configure setup steps for Copilot code review separately from Copilot cloud agent with a copilot-code-review.yml file. Read the docs for details.

Vitest treated a leaked hash-scroll setTimeout as an unhandled error
(document is not defined) after SettingsSearch tests unmounted.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5b104204-65b7-4d04-90a4-e2d5897b8e2e
Copilot AI review requested due to automatic review settings September 17, 2026 19:23

Copilot AI commented Sep 17, 2026

Copy link
Copy Markdown

One or more custom setup steps configured for this repository failed during this Copilot code review run:

Verify TypeScript build

Setup steps run before each review. If the review above is missing context, or no review was posted at all, the failing step above may be the cause. See the workflow run for failure details, fix your setup steps configuration, and re-request a review.

Note

You can configure setup steps for Copilot code review separately from Copilot cloud agent with a copilot-code-review.yml file. Read the docs for details.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The changes consistently address null-slice handling across API + UI, and include focused regression tests covering the reported crash scenario.

Review details
  • Files reviewed: 17/17 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@atulmgupta
atulmgupta merged commit 0c9aee6 into main Sep 17, 2026
23 of 24 checks passed
@atulmgupta
atulmgupta deleted the fix/journeys-null-length branch September 17, 2026 20:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants