Skip to content

fix: Enhance validation in controllers and filters to handle missing …#1201

Open
gibahjoe wants to merge 2 commits into
mainfrom
2584-sentry-template-render-error
Open

fix: Enhance validation in controllers and filters to handle missing …#1201
gibahjoe wants to merge 2 commits into
mainfrom
2584-sentry-template-render-error

Conversation

@gibahjoe
Copy link
Copy Markdown
Contributor

@gibahjoe gibahjoe commented Jun 3, 2026

Description

Fixes a submit journey crash where datasetSlugToReadableName could be called with a missing dataset, causing Cannot read properties of undefined (reading 'charAt').

The submit journey now redirects users back to /check/url when required session data is missing, and the shared page controller avoids formatting a dataset name unless a dataset exists. The dataset name filter also has a defensive fallback for missing slugs.

What type of PR is this? (check all applicable)

  • Refactor
  • Feature
  • Bug Fix
  • Optimization
  • Documentation Update

Related Tickets & Documents

QA Instructions, Screenshots, Recordings

Run the focused unit tests:

npx vitest run test/unit/PageController.test.js test/unit/lpaDetailsController.test.js test/unit/checkAnswersController.test.js test/unit/makeDatasetSlugToReadableNameFilter.test.js

Expected result: all tests pass.

Manual QA:

  • Start from a valid check URL result and continue into the submit journey.
  • Confirm /submit/lpa-details, /submit/dataset-details, and /submit/check-answers still render correctly when session data is valid.
  • Try visiting /submit/dataset-details or /submit/check-answers without a valid submit session.
  • Confirm the user is redirected to /check/url instead of seeing a server error.

Before

The check answers page could throw:

TypeError: Cannot read properties of undefined (reading 'charAt')

when values['dataset'] was missing.

After

Missing required submit journey data redirects the user to /check/url, and the dataset name formatter is not called with a missing dataset.

Added/updated tests?

  • Yes
  • No, and this is why:
  • I need help with writing tests

QA sign off

  • Code has been checked and approved
  • Design has been checked and approved
  • Product and business logic has been checked and proved

[optional] Are there any post-deployment tasks we need to perform?

None.

[optional] Are there any dependencies on other PRs or Work?

None.

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Enhanced validation to ensure both request identifier and dataset are present; requests with missing values now redirect to the appropriate error page.
    • Improved handling of missing or invalid dataset information throughout the application.
    • Added safeguards to prevent processing when dataset information is unavailable.
  • Tests

    • Expanded test coverage for missing dataset scenarios and edge cases.

@gibahjoe gibahjoe linked an issue Jun 3, 2026 that may be closed by this pull request
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

Warning

Review limit reached

@gibahjoe, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 54 minutes and 31 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 95c577ad-f660-4e55-ac3e-ea548031ed69

📥 Commits

Reviewing files that changed from the base of the PR and between 79385ad and 729de06.

📒 Files selected for processing (2)
  • src/controllers/lpaDetailsController.js
  • test/unit/lpaDetailsController.test.js

Walkthrough

Controllers and filters now consistently validate that dataset exists in the session before proceeding. LpaDetailsController adds a fallback to retrieve requestId from sessionModel when checkRequestId is absent. PageController and the dataset-slug filter now handle missing dataset values gracefully without attempting downstream lookups.

Changes

Dataset presence validation and session resilience

Layer / File(s) Summary
Dataset validation in request-handling controllers
src/controllers/CheckAnswersController.js, src/controllers/datasetDetailsController.js
CheckAnswersController and DatasetDetailsController now expand their redirect guards to require both requestId and dataset to be present in the session before proceeding; if either is missing, they redirect to /check/url.
LpaDetailsController session fallback and enhanced validation
src/controllers/lpaDetailsController.js
LpaDetailsController now uses a nullish-coalescing fallback to derive requestId from sessionModel when checkRequestId is not set, updates the request-param validation to require both type === 'check_url' and a truthy dataset, and interpolates the local requestId variable into lastPage instead of reading from req.session.
Downstream dataset handling in filters and views
src/controllers/pageController.js, src/filters/makeDatasetSlugToReadableNameFilter.js
PageController now only attempts to derive the readable dataset name when a dataset value is present in sessionModel, and makeDatasetSlugToReadableNameFilter now guards against falsy slug inputs by logging a debug message and returning the slug unchanged rather than attempting a mapping lookup.
Test coverage for dataset validation and fallback logic
test/unit/checkAnswersController.test.js, test/unit/lpaDetailsController.test.js, test/unit/PageController.test.js, test/unit/makeDatasetSlugToReadableNameFilter.test.js
Unit tests added to verify redirect behaviour when dataset is missing from CheckAnswersController and DatasetDetailsController, fallback requestId lookup and lastPage assignment in LpaDetailsController, graceful handling of missing dataset in PageController, and safe handling of falsy slug inputs in the dataset-slug filter.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • digital-land/submit#1042: Both PRs modify LpaDetailsController.locals in src/controllers/lpaDetailsController.js to add/adjust session-model guards around dataset presence and redirect behaviour.

Suggested labels

bug

Suggested reviewers

  • DilwoarH
  • rosado
  • p3dr0migue1

Poem

A rabbit hops through guards so fine,
Dataset checks on every line,
Fallbacks catch what might be lost,
Session models know the cost,
Safe and sound, the data flows. 🐰✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The pull request addresses a server crash caused by missing dataset validation, but issue #258 is a spike focused on page content options and copy updates, not crash fixes. Verify that this pull request correctly closes issue #258 or link the appropriate issue addressing the dataset validation crash and TypeError handling.
Title check ❓ Inconclusive The title is incomplete and truncated with ellipsis, making it unclear what specific validation enhancements are being addressed. Complete the pull request title to clearly specify what missing data is being handled, e.g. 'fix: Enhance validation to handle missing dataset in controllers and filters'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Out of Scope Changes check ✅ Passed All changes are focused on adding defensive validation for missing dataset values across controllers and filters with corresponding test coverage.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 2584-sentry-template-render-error

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 66.25% 7127 / 10757
🔵 Statements 66.25% 7127 / 10757
🔵 Functions 63.53% 291 / 458
🔵 Branches 77.79% 974 / 1252
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/controllers/CheckAnswersController.js 87.5% 70.37% 100% 87.5% 17-19, 23-29, 153-159, 166, 183-188
src/controllers/datasetDetailsController.js 0% 0% 0% 0% 1-28
src/controllers/lpaDetailsController.js 95.23% 90% 100% 95.23% 24-25
src/controllers/pageController.js 87.87% 86.36% 80% 87.87% 20-21, 46-50, 75-79
src/filters/makeDatasetSlugToReadableNameFilter.js 100% 100% 100% 100%
Generated in workflow #1485 for commit 729de06 by the Vitest Coverage Report Action

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/controllers/lpaDetailsController.js`:
- Line 8: The code in lpaDetailsController sets requestId from
req.session?.checkRequestId but falls back only to
req.sessionModel.get('request_id'), while other controllers store/read the
camelCase key; update the fallback logic in lpaDetailsController so requestId is
resolved by checking req.session?.checkRequestId first, then
req.sessionModel.get('requestId') and finally req.sessionModel.get('request_id')
to cover both stored formats; locate the assignment to requestId in
lpaDetailsController and adjust the fallback order accordingly.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8fcdaccc-3937-41f4-8f4c-8b80ebc8a8da

📥 Commits

Reviewing files that changed from the base of the PR and between 1f339c3 and 79385ad.

📒 Files selected for processing (9)
  • src/controllers/CheckAnswersController.js
  • src/controllers/datasetDetailsController.js
  • src/controllers/lpaDetailsController.js
  • src/controllers/pageController.js
  • src/filters/makeDatasetSlugToReadableNameFilter.js
  • test/unit/PageController.test.js
  • test/unit/checkAnswersController.test.js
  • test/unit/lpaDetailsController.test.js
  • test/unit/makeDatasetSlugToReadableNameFilter.test.js

Comment thread src/controllers/lpaDetailsController.js Outdated
class LpaDetailsController extends PageController {
async locals (req, res, next) {
const requestId = req.session?.checkRequestId
const requestId = req.session?.checkRequestId ?? req.sessionModel.get('request_id')
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find all session-model reads/writes that look like a request id key
rg -nP "sessionModel\.(get|set)\(\s*['\"](request_id|requestId)['\"]" --type=js
echo "----- checkRequestId usages -----"
rg -nP "checkRequestId" --type=js -C2

Repository: digital-land/submit

Length of output: 2757


Fix session key fallback in lpaDetailsController (request_id vs requestId)

src/controllers/lpaDetailsController.js reads req.sessionModel.get('request_id') when req.session?.checkRequestId is unset, but it stores requestId in the session model and other controllers use requestId (e.g. datasetDetailsController.js, CheckAnswersController.js, endpointSubmissionFormDeepLinkController.js). If only requestId is present and checkRequestId is not set, requestId will become undefined and the page will not get the expected value (the existing unit test currently only covers the request_id case).

🔧 Proposed fix (read both keys)
-    const requestId = req.session?.checkRequestId ?? req.sessionModel.get('request_id')
+    const requestId = req.session?.checkRequestId ?? req.sessionModel.get('requestId') ?? req.sessionModel.get('request_id')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/controllers/lpaDetailsController.js` at line 8, The code in
lpaDetailsController sets requestId from req.session?.checkRequestId but falls
back only to req.sessionModel.get('request_id'), while other controllers
store/read the camelCase key; update the fallback logic in lpaDetailsController
so requestId is resolved by checking req.session?.checkRequestId first, then
req.sessionModel.get('requestId') and finally req.sessionModel.get('request_id')
to cover both stored formats; locate the assignment to requestId in
lpaDetailsController and adjust the fallback order accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sentry Template render error Spike: Options/proposal for the content of the page

1 participant