Skip to content

fix(rivetkit): validate runner version fits in u32#4417

Open
NathanFlurry wants to merge 1 commit intomainfrom
fix/runner-version-u32-validation
Open

fix(rivetkit): validate runner version fits in u32#4417
NathanFlurry wants to merge 1 commit intomainfrom
fix/runner-version-u32-validation

Conversation

@NathanFlurry
Copy link
Member

Summary

  • The runner protocol (BARE schema) uses u32 for runner version, but nothing prevented the TypeScript client from sending values that overflow it
  • Sandbox Agent was hitting this: Date.now() (milliseconds) produces values like 1773390978291 which exceed u32::MAX (4294967295), causing the engine's metadata endpoint to return invalid_response_json
  • Adds zod validation on the runner version config: must be a non-negative integer that fits in u32, with a helpful error message suggesting Date.now() / 1000 if the value is too large

Test plan

  • Verify that setting a runner version > 4294967295 causes a startup validation error
  • Verify that Math.floor(Date.now() / 1000) still works as a valid version
  • Verify existing default version (1) still works

@railway-app
Copy link

railway-app bot commented Mar 13, 2026

🚅 Deployed to the rivet-pr-4417 environment in rivet-frontend

Service Status Web Updated (UTC)
frontend-inspector 😴 Sleeping (View Logs) Web Mar 13, 2026 at 9:33 am
website 😴 Sleeping (View Logs) Web Mar 13, 2026 at 9:31 am
frontend-cloud 😴 Sleeping (View Logs) Web Mar 13, 2026 at 9:30 am
ladle ❌ Build Failed (View Logs) Web Mar 13, 2026 at 9:22 am
mcp-hub ✅ Success (View Logs) Web Mar 13, 2026 at 9:21 am

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 13, 2026

More templates

@rivetkit/virtual-websocket

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/virtual-websocket@4417

@rivetkit/cloudflare-workers

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/cloudflare-workers@4417

@rivetkit/framework-base

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/framework-base@4417

@rivetkit/next-js

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/next-js@4417

@rivetkit/react

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/react@4417

rivetkit

pnpm add https://pkg.pr.new/rivet-dev/rivet/rivetkit@4417

@rivetkit/sql-loader

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/sql-loader@4417

@rivetkit/sqlite-vfs

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/sqlite-vfs@4417

@rivetkit/traces

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/traces@4417

@rivetkit/workflow-engine

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/workflow-engine@4417

@rivetkit/engine-runner

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner@4417

@rivetkit/engine-runner-protocol

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner-protocol@4417

commit: 0d2d262

@claude
Copy link

claude bot commented Mar 13, 2026

PR Review

This is a clean, targeted fix for a real bug. The root cause is well-identified and the solution is minimal.

Positive observations

  • The error message is excellent: it names the constraint, explains the cause, and gives a concrete fix (Date.now() / 1000).
  • The chain of .int().min(0).max(...) correctly covers all overflow edge cases: floats, negatives, and values exceeding u32 max.
  • The next-js package already uses Math.floor(Date.now() / 1000), so this validates that existing usage is already correct.

Minor issues

totalSlots has the same u32 constraint without validation

rivetkit-typescript/packages/rivetkit/src/registry/config/runner.ts:11

totalSlots is also serialized as u32 in ToServerInit (runner-protocol src/index.ts:1561) but has no upper bound check. The default (100000) is safe, but a user passing an env var or explicit config value exceeding 4294967295 would silently corrupt the BARE frame. Consider adding the same guard, or at least a comment noting the engine-side constraint.

getRivetRunnerVersion can produce NaN

rivetkit-typescript/packages/rivetkit/src/utils/env-vars.ts:31

parseInt(value, 10) returns NaN for non-numeric env var strings. Zod's .int() rejects NaN, but the resulting error message ("Expected integer, received nan") is less helpful than a dedicated check. Not a blocker, but worth noting.

No automated tests for the validation

The PR's own test plan is manual. A short unit test exercising the schema with values like Date.now(), 4294967295, 4294967296, and -1 would lock in the constraint and prevent future regressions. The existing test infrastructure (pnpm test in rivetkit-typescript/packages/rivetkit) could host these cheaply.

Summary

The fix is correct and the change is minimal. The two guard gaps (totalSlots and NaN from parseInt) are pre-existing issues rather than regressions introduced here, but worth a follow-up. Adding automated tests is the most impactful next step.

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.

1 participant