fix: validate req.body.code in compileResume middleware (#1622) - #1722
fix: validate req.body.code in compileResume middleware (#1622)#1722suhaniiz wants to merge 4 commits into
Conversation
📝 WalkthroughWalkthrough
ChangesResume validation
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 Biome (2.5.6)backend/Input_validators/ValidateResume.jsFile contains syntax errors that prevent linting: Line 124: expected Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@backend/Input_validators/ValidateResume.js`:
- Around line 56-59: Update the validation failure path around
analyzeResumeSchema.safeParse to delete any uploaded temporary file before
returning handleValidationError. Reuse the existing upload cleanup mechanism, if
available, and ensure cleanup runs for rejected requests that include a file
without changing the validation response.
🪄 Autofix
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 Plus
Run ID: 6d4c3b79-4248-4885-8cde-bb421a14722b
📒 Files selected for processing (1)
backend/Input_validators/ValidateResume.js
| .string({ | ||
| required_error: "LaTeX code is required", | ||
| invalid_type_error: "LaTeX code must be a string", | ||
| }) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
Zod 4 migration guide required_error invalid_type_error unified error parameter
💡 Result:
In Zod 4, error customization has been standardized under a single, unified error parameter, replacing the previously fragmented API [1][2]. Key migration points: 1. Unified Error Parameter: The legacy message parameter (often used for simple string overrides) has been deprecated in favor of the error parameter [1][2]. This new parameter accepts an error map function, allowing for consistent error handling across the library [3][4]. 2. Deprecation of Fragmented APIs: Previous approaches to customizing errors—such as passing separate error messages or using inconsistent configuration objects—have been cleaned up to improve cohesion [1][2]. 3. Error Maps: Error customization is now centrally managed through error maps. These functions receive an issue object (iss), which is a discriminated union of all possible issue types, allowing you to handle specific codes like invalid_type or too_small precisely [3][4]. 4. Migration Assistance: An unofficial community-maintained codemod (zod-v3-to-v4) is available to automate many of these breaking changes [1]. Official documentation suggests reading the Zod 4 migration guide thoroughly as it lists changes in order of impact [1][2]. To upgrade to Zod 4, install the latest version: npm install zod@^4.0.0 [5][6] For detailed customization examples, including per-parse and global configurations using the unified error approach, refer to the Zod 4 error customization documentation [3][4].
Citations:
- 1: https://zod.dev/v4/changelog
- 2: https://github.com/colinhacks/zod/blob/c7805073/packages/docs/content/v4/changelog.mdx
- 3: https://zod.dev/error-customization
- 4: https://github.com/colinhacks/zod/blob/v4.4.3/packages/docs/content/error-customization.mdx
- 5: https://zod.dev/v4
- 6: https://github.com/colinhacks/zod/blob/c7805073/packages/docs/content/v4/index.mdx
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- candidate files ---'
git ls-files | grep -E '(^|/)(ValidateResume\.js|package\.json|package-lock\.json|yarn\.lock|pnpm-lock\.yaml)$' || true
printf '%s\n' '--- validator source ---'
file=$(git ls-files | grep 'backend/Input_validators/ValidateResume\.js$' | head -n 1)
if [ -n "${file:-}" ]; then
cat -n "$file"
fi
printf '%s\n' '--- Zod dependency declarations ---'
while IFS= read -r f; do
case "$f" in
*package.json|*package-lock.json|*yarn.lock|*pnpm-lock.yaml)
grep -nE '"zod"|(^|[[:space:]])zod([@[:space:]:]|$)' "$f" || true
;;
esac
done < <(git ls-files | grep -E '(^|/)(package\.json|package-lock\.json|yarn\.lock|pnpm-lock\.yaml)$')
printf '%s\n' '--- validator usages ---'
rg -n --glob '!node_modules' 'ValidateResume|resumeSchema|latexCode|title: z\.string' backend . || trueRepository: Canopus-Labs/PrepPilot
Length of output: 3460
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
import json
from pathlib import Path
for name in ["package.json", "backend/package.json", "frontend/package.json"]:
p = Path(name)
if not p.exists():
continue
data = json.loads(p.read_text())
deps = {}
deps.update(data.get("dependencies", {}))
deps.update(data.get("devDependencies", {}))
print(f"{name}: zod declaration = {deps.get('zod', '<absent>')}")
for name in ["package-lock.json", "backend/package-lock.json", "frontend/package-lock.json"]:
p = Path(name)
if not p.exists():
continue
data = json.loads(p.read_text())
versions = set()
packages = data.get("packages", {})
for key, value in packages.items():
if key.endswith("/node_modules/zod") or key == "node_modules/zod":
if "version" in value:
versions.add(value["version"])
if not versions:
root = data.get("dependencies", {}).get("zod", {})
if root.get("version"):
versions.add(root["version"])
print(f"{name}: locked zod versions = {sorted(versions) or '<absent>'}")
PY
printf '%s\n' '--- all Zod declarations/usages ---'
rg -n --glob '!node_modules' --glob '*package*.json' --glob '*lock*' '"zod"|node_modules/zod' . || trueRepository: Canopus-Labs/PrepPilot
Length of output: 662
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- validation error handling ---'
file=$(git ls-files | grep 'backend/Input_validators/ValidateQuestions\.js$' | head -n 1)
if [ -n "${file:-}" ]; then
cat -n "$file"
fi
printf '%s\n' '--- validation message consumers and tests ---'
rg -n --glob '!node_modules' 'LaTeX code is required|LaTeX code must be a string|Title is required|Title must be a string|required_error|invalid_type_error|validateCompileResume|validateSaveResume|handleValidationError' backend . || true
printf '%s\n' '--- Zod lockfile package metadata ---'
python3 - <<'PY'
import json
from pathlib import Path
p = Path("backend/package-lock.json")
data = json.loads(p.read_text())
for key, value in data.get("packages", {}).items():
if key.endswith("/node_modules/zod"):
print(key, value)
PYRepository: Canopus-Labs/PrepPilot
Length of output: 16477
🌐 Web query:
site:zod.dev/v4/changelog required_error invalid_type_error removed Zod 4
💡 Result:
In Zod 4, the previously used invalid_type_error and required_error parameters have been removed to standardize error customization [1]. These parameters were removed because they were inconsistent, conflicted with errorMap usage, and did not align with Zod's internal issue codes (as there is no native 'required' issue code) [1]. To replace this functionality, Zod 4 introduces a unified error parameter that accepts a function [1]. This function receives the ZodIssue object and allows for logic-based error message customization [1]. For example, to replicate the behavior of a required field error: z.string({ error: (issue) => issue.input === undefined? "This field is required": "Not a string" }); By returning undefined from this function, you can also signal Zod to fall back to the next error map in the chain [1].
Citations:
Replace the removed Zod 4 error options.
Use error customization for code, title, and latexCode. Zod 4 removed required_error and invalid_type_error, so these fields currently use default messages for missing and non-string inputs.
📍 Affects 1 file
backend/Input_validators/ValidateResume.js#L10-L13(this comment)backend/Input_validators/ValidateResume.js#L27-L34
|
@suhaniiz Address the coderabbit suggestions and resolve the merge conflicts |
|
@KaranUnique , resolved |
|
@suhaniiz, please resolve the commit so that it will be merged soon ...... |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
backend/Input_validators/ValidateResume.js (3)
61-68: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick winRemove the conflicting middleware implementations. The module contains unresolved alternative implementations for both compile and analyze validation. These declarations make
ValidateResume.jsfail to parse, so no exported validator can load.
backend/Input_validators/ValidateResume.js#L61-L68: retain onevalidateCompileResumedeclaration that validatesreq.body || {}.backend/Input_validators/ValidateResume.js#L72-L104: retain one completevalidateAnalyzeResumedeclaration and keep cleanup for rejected uploaded files.🤖 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 `@backend/Input_validators/ValidateResume.js` around lines 61 - 68, In backend/Input_validators/ValidateResume.js lines 61-68, remove the duplicate validateCompileResume declaration and retain one implementation that validates req.body || {}. In lines 72-104, remove the conflicting validateAnalyzeResume implementation and retain one complete declaration, preserving cleanup of rejected uploaded files.
46-56: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winRestore the
mongoosebinding before ObjectId validation.
mongoose.isValidObjectIdhas no imported binding. A save request with a non-emptyresumeId, or any delete request with anid, can throw instead of returning a validation response. Restore the import or replace both calls with an imported ObjectId validator.🤖 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 `@backend/Input_validators/ValidateResume.js` around lines 46 - 56, Restore the mongoose binding in ValidateResume.js, or use an imported ObjectId validator, so both resumeId validation in the resume schema and id validation in deleteResumeSchema can call isValidObjectId without a ReferenceError. Preserve the existing optional resumeId behavior and validation messages.
31-49: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winRemove the duplicate schema keys.
The final declarations at Lines 44-49 overwrite the earlier
title,latexCode, andresumeIddefinitions. Keep one definition for each field so the active validation contract is explicit.🤖 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 `@backend/Input_validators/ValidateResume.js` around lines 31 - 49, Remove the duplicate title, latexCode, and resumeId declarations from the schema, keeping one definition for each field. Preserve the earlier definitions with required and invalid-type messages, and retain the mongoose.isValidObjectId refinement on resumeId by incorporating it into that single definition.Source: Linters/SAST tools
🤖 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.
Outside diff comments:
In `@backend/Input_validators/ValidateResume.js`:
- Around line 61-68: In backend/Input_validators/ValidateResume.js lines 61-68,
remove the duplicate validateCompileResume declaration and retain one
implementation that validates req.body || {}. In lines 72-104, remove the
conflicting validateAnalyzeResume implementation and retain one complete
declaration, preserving cleanup of rejected uploaded files.
- Around line 46-56: Restore the mongoose binding in ValidateResume.js, or use
an imported ObjectId validator, so both resumeId validation in the resume schema
and id validation in deleteResumeSchema can call isValidObjectId without a
ReferenceError. Preserve the existing optional resumeId behavior and validation
messages.
- Around line 31-49: Remove the duplicate title, latexCode, and resumeId
declarations from the schema, keeping one definition for each field. Preserve
the earlier definitions with required and invalid-type messages, and retain the
mongoose.isValidObjectId refinement on resumeId by incorporating it into that
single definition.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 63abc797-04d9-46a7-bd40-48106dda5e51
📒 Files selected for processing (1)
backend/Input_validators/ValidateResume.js
|
@KaranUnique , conflicts resolved |
|
@suhaniiz, please resolve the commit so that it will be merged soon ...... |
📝 Pull Request Description
Related Issue
Closes #1622
Summary
Fixes an issue where
POST /api/resume/compilereturned a500 Internal Server Errorinstead of a400 Bad Requestwhenreq.bodyorreq.body.codewas missing or undefined.Updated the validation middleware to use Zod's
safeParsewith an(req.body || {})fallback, ensuring missing body payloads are caught early and handled gracefully with proper standard 400 validation error responses.Type of Change
How Has This Been Tested?
POSTrequests to/api/resume/compilewith an empty JSON payload{}and confirmed it returns400 Bad Requestwith{"message": "LaTeX code is required"}instead of throwing an unhandledTypeError.{"code": 123}) trigger proper Zod validation error messages.Screenshots (if applicable)
N/A
Checklist
Looks good to me. Ready to merge.