Skip to content

fix(vercel-api): normalize engines.node and drop nowConfig payload field - #364

Merged
amondnet merged 11 commits into
masterfrom
amondnet/fix-359-node-errors
Apr 30, 2026
Merged

fix(vercel-api): normalize engines.node and drop nowConfig payload field#364
amondnet merged 11 commits into
masterfrom
amondnet/fix-359-node-errors

Conversation

@amondnet

@amondnet amondnet commented Apr 29, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes two deployment-failure regressions in v42.2.1 (PR #350) reported in #359.

Bug 1 — projectSettings.nodeVersion rejected (HTTP 400)

The Vercel REST API only accepts the canonical shorthand "24.x", "22.x", or "20.x". v42.2.1 forwarded package.json engines.node verbatim, so consumers with semver ranges (>=24.0.0, ^20.0.0) or exact versions (24.0.0) hit Invalid request: projectSettings.nodeVersion should be equal to one of the allowed values "24.x, 22.x, 20.x".

Fix: New normalizeNodeVersion helper in src/project-config.ts using semver.intersects against a hardcoded list of supported Vercel majors. Iteration is highest-first to mirror Vercel CLI parity (@vercel/build-utils.getSupportedNodeVersion walks [24, 22, 20] descending). For unsupported inputs the field is omitted with a core.warning, so the deployment falls back to the project's default Node version instead of failing.

Bug 2 — nowConfig rejected as additional property (HTTP 400)

v42.2.1 attached nowConfig (parsed vercel.json contents) as a top-level field on DeploymentOptions. @vercel/client.postDeployment raw-spreads DeploymentOptions into the request body, so the Vercel REST API rejected nowConfig as additionalProperty. The Vercel CLI does not send nowConfig; it copies a select set of vercel.json keys into projectSettings instead.

Fix: Drop the nowConfig field entirely. Replace sanitizeNowConfig with a static PROJECT_SETTINGS_KEYS whitelist (buildCommand, installCommand, outputDirectory, framework, devCommand) copied into projectSettings from vercel.json. The static whitelist also makes the prior prototype-pollution stripping unnecessary by construction.

Changes

  • package.json — promote semver from transitive to direct dep; add @types/semver.
  • src/project-config.ts — add normalizeNodeVersion; replace nowConfig with PROJECT_SETTINGS_KEYS whitelist; warning path for unsupported engines.node.
  • src/vercel-api.ts — drop nowConfig assignment in applyProjectConfig; correct misleading comment block.
  • src/__tests__/project-config.test.ts — 11 new normalization cases + lockdown for projectSettings whitelist.
  • src/__tests__/vercel-api.test.ts — rewrite the three tests that asserted the broken nowConfig behavior; add a combined regression test.
  • src/__integration__/vercel-api.test.ts — emulator-based regression test for semver-range engines.node + vercel.json buildCommand together.
  • dist/ — rebuilt.

Verification Checklist

  • pnpm run all (lint + typecheck + build + test) passes locally.
  • GITHUB_REPOSITORY=test-owner/test-repo pnpm test — full suite green (249/249).
  • pnpm test:coverageproject-config.ts 93.63%, vercel-api.ts 90.78% (no regression).
  • pnpm run builddist/index.js rebuilt and committed.
  • End-to-end smoke (recommended before tagging release): push a test branch with engines.node: ">=24.0.0" and vercel.json: { "buildCommand": "./build.sh" } and confirm deployment succeeds against a real Vercel project.
  • CI on this PR passes (GitHub Actions).

Track

.please/docs/tracks/active/fix-vercel-validation-20260430/ — spec, investigation, plan, and progress log.

Closes #359


Summary by cubic

Normalize engines.node to Vercel’s NN.x enum, drop the rejected nowConfig, and harden vercel.json key handling to prevent API 400s. Restores deployments, matches Vercel CLI behavior, and fixes #359.

  • Bug Fixes

    • Map package.json engines.node to "24.x", "22.x", or "20.x" using semver (highest-first to match CLI). Omit unsupported or discontinued inputs with a warning.
    • Stop sending nowConfig. Copy only whitelisted vercel.json keys into projectSettings (buildCommand, installCommand, outputDirectory, framework, devCommand) when Object.hasOwn(vercelJson, key) is true and the value is a string or null; warn on other types.
  • Dependencies

    • Add semver and @types/semver.

Written for commit bf518df. Summary will update on new commits. Review in cubic

The Vercel REST API only accepts "24.x", "22.x", or "20.x" for
projectSettings.nodeVersion. v42.2.1 forwarded the raw `engines.node`
value verbatim, so consumers with semver ranges (">=24.0.0", "^20.0.0")
or exact versions ("24.0.0") hit 400 bad_request.

Add a local `normalizeNodeVersion` helper using `semver.intersects`
against a hardcoded list of supported Vercel majors. Map any matching
range to the canonical "NN.x" form. For unsupported inputs, omit the
field with a warning so the deployment falls back to the project default
instead of failing.

`semver` is promoted from a transitive dependency to a direct one, with
`@types/semver` for type support.

Refs #359
The Vercel REST API rejects nowConfig as an undeclared additional
property (HTTP 400). PR #350 attached it to DeploymentOptions based on
a misreading of the API contract; the Vercel CLI never sends it.

Mirror the CLI by copying a static whitelist of vercel.json keys —
buildCommand, installCommand, outputDirectory, framework, devCommand —
into projectSettings instead. Drop the nowConfig field from
ProjectConfig and the assignment in applyProjectConfig. Update tests
that asserted the broken behavior.

The static whitelist also makes the prior images / __proto__ /
constructor / prototype stripping unnecessary by construction.

Refs #359
Combine both bugs into one scenario at unit and integration levels:
package.json with engines.node ">=24.0.0" plus vercel.json with
buildCommand. Assert the resulting payload normalizes nodeVersion to
"24.x", forwards buildCommand via projectSettings, and contains no
top-level nowConfig.

The integration test additionally tolerates known emulator network
errors but rejects any error message mentioning projectSettings.nodeVersion
or nowConfig — these would indicate the bugs have re-emerged.

Refs #359
Bundles semver dependency, normalizeNodeVersion helper, and the
projectSettings whitelist replacing nowConfig.

Refs #359
Reviewer caught divergence from `@vercel/build-utils.getSupportedNodeVersion`,
which iterates supported majors in descending order and returns the first
intersecting match. Flipping VERCEL_NODE_VERSIONS to ['24.x', '22.x', '20.x']
means `engines.node: '>=18'` now resolves to '24.x' (matching `vc deploy`)
instead of '20.x'.

Also clarify the unsupported-version warning to distinguish discontinued
majors (e.g. 18.x) from malformed input, and add an explicit test for the
discontinued-major case.

Refs #359
Copilot AI review requested due to automatic review settings April 29, 2026 19:35
@github-actions

github-actions Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Deploy preview for file ready!

Project:file
Status: ✅  Deploy successful!
Preview URL:https://team-scope-test-l8bz1gjj1-dietfriends.vercel.app
Latest Commit:bf518df
Inspect:View deployment

Deployed with vercel-action

@github-actions

github-actions Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Deploy preview for static ready!

Project:static
Status: ✅  Deploy successful!
Preview URL:https://zeit-now-deployment-action-example-angular-e6q85k07m.vercel.app
Latest Commit:bf518df
Alias:https://staging.static.vercel-action.amond.dev
Alias:https://pr-364.static.vercel-action.amond.dev
Inspect:View deployment

Deployed with vercel-action

@github-actions

github-actions Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Deploy preview for express-basic-auth ready!

Project:express-basic-auth
Status: ✅  Deploy successful!
Preview URL:https://express-basic-auth-h669kriww-minsu-lees-projects-b1e388b7.vercel.app
Latest Commit:bf518df
Inspect:View deployment

Deployed with vercel-action

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.

Pull request overview

Fixes Vercel REST API validation regressions introduced in v42.2.1 by (1) normalizing projectSettings.nodeVersion to Vercel’s accepted "NN.x" enum and (2) removing the invalid top-level nowConfig payload field, while still honoring key vercel.json settings via projectSettings.

Changes:

  • Add normalizeNodeVersion() (semver-based) and omit projectSettings.nodeVersion when it can’t be mapped to 24.x | 22.x | 20.x (warn instead of hard-failing).
  • Drop nowConfig entirely; copy a small whitelist of vercel.json keys into projectSettings.
  • Update unit + integration tests and rebuild dist/ artifacts.

Reviewed changes

Copilot reviewed 12 out of 17 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/project-config.ts Adds node version normalization and copies whitelisted vercel.json keys into projectSettings (removes nowConfig).
src/vercel-api.ts Stops attaching nowConfig to DeploymentOptions; updates comment to reflect REST API constraints.
src/tests/project-config.test.ts Adds unit coverage for normalization + locks down the projectSettings whitelist behavior.
src/tests/vercel-api.test.ts Updates deployment payload assertions to ensure no nowConfig is sent and projectSettings is populated.
src/integration/vercel-api.test.ts Adds emulator-based regression coverage for the combined engines.node + vercel.json scenario.
package.json Promotes semver to a direct dependency; adds @types/semver.
pnpm-lock.yaml Records the new direct dependency/type additions and lockfile updates.
dist/index.js Rebuilt bundle including semver and the updated deployment payload behavior.
dist/project-config.d.ts Updates typings: removes nowConfig, adds new projectSettings keys and normalizeNodeVersion() export.
dist/licenses.txt Adds the semver license text to the bundled licenses.
.please/docs/tracks/active/fix-vercel-validation-20260430/spec.md Adds written spec for the regression and intended fixes.
.please/docs/tracks/active/fix-vercel-validation-20260430/plan.md Adds implementation plan and verification checklist.
.please/docs/tracks/active/fix-vercel-validation-20260430/investigation.md Adds investigation notes and root-cause analysis for #359.
.please/docs/tracks/active/fix-vercel-validation-20260430/metadata.json Adds track metadata for the bugfix workstream.
.please/docs/tracks.jsonl Registers the new active track entry.
.please/docs/knowledge/tech-stack.md Documents semver usage as part of the repo’s tech stack knowledge.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/project-config.ts

@cubic-dev-ai cubic-dev-ai Bot 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.

0 issues found across 5 files (changes from recent commits).

Requires human review: Fixes a regression by modifying core logic in the deployment payload construction and adds 'semver' as a production dependency. Requires human review to verify the normalization logic.

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request resolves deployment validation errors (Issue #359) by normalizing engines.node versions to Vercel's canonical NN.x format and replacing the nowConfig field with a whitelisted set of projectSettings. The implementation introduces the semver package for version range intersection and includes updated unit and integration tests. Feedback suggests adding runtime type validation when copying values from vercel.json to projectSettings to prevent potential API errors from non-string inputs.

Comment thread src/project-config.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot 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.

1 issue found across 17 files

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="src/project-config.ts">

<violation number="1" location="src/project-config.ts:133">
P2: Use an own-property check instead of `in` so only keys explicitly present in `vercel.json` are copied.

(Based on your team's feedback about asserting own properties when guarding against prototype-pollution behavior.) [FEEDBACK_USED]</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/project-config.ts Outdated
@amondnet amondnet self-assigned this Apr 30, 2026
Apply suggestions from cubic, gemini, and copilot review threads on
PR #364:

- Use `Object.hasOwn(vercelJson, key)` instead of `key in vercelJson`
  so prototype-chain properties cannot leak into projectSettings even if
  upstream code mutates Object.prototype (cubic, copilot).
- Type-guard whitelisted vercel.json values: only string and null pass
  through to projectSettings. Other types surface a local warning
  instead of producing a 400 from the Vercel API (gemini).

Add tests for both behaviors: explicit null sentinel preservation and
rejection of non-string/non-null values.

Refs #359, PR #364
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
14.4% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@cubic-dev-ai cubic-dev-ai Bot 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.

0 issues found across 4 files (changes from recent commits).

Requires human review: This PR modifies the request shape sent to the Vercel API and introduces logic for Node version normalization, which falls under core logic and API changes requiring human review.

@amondnet
amondnet merged commit 31671aa into master Apr 30, 2026
12 of 16 checks passed
@amondnet
amondnet deleted the amondnet/fix-359-node-errors branch April 30, 2026 00:17
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.

Multiple errors after last version v42.2.1

2 participants