Skip to content

fix: coerce duration props to Number() in renderers#183

Open
SecurityQQ wants to merge 1 commit intomainfrom
fix/duration-string-to-number
Open

fix: coerce duration props to Number() in renderers#183
SecurityQQ wants to merge 1 commit intomainfrom
fix/duration-string-to-number

Conversation

@SecurityQQ
Copy link
Copy Markdown
Contributor

Summary

  • Added Number() coercion for duration props in video, music, and resolve renderers
  • Defense-in-depth fix: if user TSX code passes duration="5" (string) instead of duration={5} (number), the SDK now coerces it before sending to the gateway

Root Cause

The duration prop flows from JSX evaluation through renderers to the gateway client without any type coercion. The gateway's VideoRequest and MusicRequest schemas use z.number().optional() (no coercion), so string durations cause "expected number, received string" validation errors.

Files Changed

  • src/react/renderers/video.ts:153props.duration ?? 5 -> Number(props.duration) || 5
  • src/react/resolve.ts:650(props.duration as number) ?? 5 -> Number(props.duration) || 5
  • src/react/renderers/music.ts:30,40props.duration -> props.duration != null ? Number(props.duration) : undefined

Behavior

  • Number(5) -> 5 (no change for correct inputs)
  • Number("5") -> 5 (fixes string inputs)
  • Number(undefined) -> NaN, NaN || 5 -> 5 (correct fallback)
  • Number("auto") -> NaN, NaN || 5 -> 5 (safe fallback for "auto")

Related

  • App fix: vargHQ/app — fix/duration-string-to-number branch fixes the AI prompt to not generate string durations

Defense-in-depth fix: if user code passes duration as a string (e.g. "5"
instead of 5), coerce it to a number before sending to the gateway.
Prevents 'expected number, received string' Zod validation errors.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 28, 2026

📝 Walkthrough

walkthrough

duration props across music, video, and resolve renderers are being standardized to use Number() coercion instead of type casting or nullish coalescing, ensuring consistent handling of non-numeric and falsy values with a fallback default.

changes

cohort / file(s) summary
duration normalization
src/react/renderers/music.ts, src/react/renderers/video.ts, src/react/resolve.ts
standardized props.duration handling using Number() coercion with falsy fallbacks instead of type casting or nullish coalescing, affecting cache keys and generator inputs.

estimated code review effort

🎯 2 (simple) | ⏱️ ~8 minutes

poem

🎵 duration flows like numbers now,
coerced and tamed, we all know how,
from cast to Number, clean and bright,
your videos and songs align just right ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed the title clearly and concisely describes the main change: adding Number() coercion for duration props across renderers.
Description check ✅ Passed the description is directly related to the changeset, providing root cause, affected files, and behavior examples for the duration coercion fix.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/duration-string-to-number

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.

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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/react/renderers/music.ts`:
- Line 30: Extract a single const duration computed once (e.g. const duration =
props.duration === undefined || props.duration === null ? undefined :
Number(props.duration)) and replace both occurrences of the current non-strict
checks and coercions (the two uses of props.duration != null and
Number(props.duration)) with that duration variable; ensure you use strict
equality (===) to check for undefined/null rather than != and then reuse
duration wherever the previous checks/coercions appeared so cache keys and
requests stay consistent.

In `@src/react/renderers/video.ts`:
- Line 153: The duration fallback currently uses "Number(props.duration) || 5",
which treats an explicit 0 as falsy and falls back to 5; update the assignment
that sets the duration (the "duration" property using props.duration) to use a
nullish check so an explicit 0 is preserved (for example, use props.duration !==
undefined/nullish-coalescing to choose between Number(props.duration) and 5) —
locate the "duration" property assignment in src/react/renderers/video.ts and
replace the || fallback with a nullish/undefined check such as using
props.duration ?? 5 or an explicit undefined check around
Number(props.duration).

In `@src/react/resolve.ts`:
- Line 650: The duration fallback currently uses "Number(props.duration) || 5"
which treats explicit 0 as falsy and overwrites it; update the duration
assignment in resolve.ts to first detect missing values (null/undefined) and
only then default to 5, otherwise coerce props.duration to a Number and fallback
to 5 if that coercion produces NaN/Infinity; reference the duration property and
props.duration so you change the expression that computes duration (replace the
current ||-based expression with a null/undefined check plus a Number.isFinite
check to preserve explicit 0).
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 45ead561-203a-4c8f-bed6-742ae3116309

📥 Commits

Reviewing files that changed from the base of the PR and between fe87945 and a924e0d.

📒 Files selected for processing (3)
  • src/react/renderers/music.ts
  • src/react/renderers/video.ts
  • src/react/resolve.ts

prompt,
model: model.modelId,
duration: props.duration,
duration: props.duration != null ? Number(props.duration) : undefined,
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 | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n src/react/renderers/music.ts | head -50

Repository: vargHQ/sdk

Length of output: 2005


switch to strict equality and extract the duration once

lines 30 and 40 both use != null and duplicate the same coercion. violates the "always use strict equality (===)" guideline, and the duplication risks cache key + request misalignment if the logic changes later. extract const duration once and reuse it instead. meow 🐱

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/react/renderers/music.ts` at line 30, Extract a single const duration
computed once (e.g. const duration = props.duration === undefined ||
props.duration === null ? undefined : Number(props.duration)) and replace both
occurrences of the current non-strict checks and coercions (the two uses of
props.duration != null and Number(props.duration)) with that duration variable;
ensure you use strict equality (===) to check for undefined/null rather than !=
and then reuse duration wherever the previous checks/coercions appeared so cache
keys and requests stay consistent.

model,
prompt: resolvedPrompt,
duration: props.duration ?? 5,
duration: Number(props.duration) || 5,
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

🧩 Analysis chain

🏁 Script executed:

cat -n src/react/renderers/video.ts | sed -n '145,165p'

Repository: vargHQ/sdk

Length of output: 909


🏁 Script executed:

rg -n "duration.*\|\|" src/react/renderers/ -A 2 -B 2

Repository: vargHQ/sdk

Length of output: 390


🏁 Script executed:

rg -n "Number.*\|\|" src/ --type ts --type tsx | head -20

Repository: vargHQ/sdk

Length of output: 81


🏁 Script executed:

rg "Number.*\|\|" src/ -A 2 -B 2

Repository: vargHQ/sdk

Length of output: 2699


fix zero duration fallback bug

line 153 has the same 0-to-5 regression as the resolve path: Number(props.duration) || 5 ignores explicit zero durations.

suggested patch
-      duration: Number(props.duration) || 5,
+      duration: Number.isFinite(Number(props.duration)) ? Number(props.duration) : 5,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
duration: Number(props.duration) || 5,
duration: Number.isFinite(Number(props.duration)) ? Number(props.duration) : 5,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/react/renderers/video.ts` at line 153, The duration fallback currently
uses "Number(props.duration) || 5", which treats an explicit 0 as falsy and
falls back to 5; update the assignment that sets the duration (the "duration"
property using props.duration) to use a nullish check so an explicit 0 is
preserved (for example, use props.duration !== undefined/nullish-coalescing to
choose between Number(props.duration) and 5) — locate the "duration" property
assignment in src/react/renderers/video.ts and replace the || fallback with a
nullish/undefined check such as using props.duration ?? 5 or an explicit
undefined check around Number(props.duration).

model: model as Parameters<typeof generateVideoRaw>[0]["model"],
prompt: resolvedPrompt,
duration: (props.duration as number) ?? 5,
duration: Number(props.duration) || 5,
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

🧩 Analysis chain

🏁 Script executed:

find . -name "resolve.ts" -path "*/react/*" -type f

Repository: vargHQ/sdk

Length of output: 76


🏁 Script executed:

cat -n ./src/react/resolve.ts | sed -n '640,660p'

Repository: vargHQ/sdk

Length of output: 910


🏁 Script executed:

# find the type definition for props in this function
rg -B 20 "duration: Number\(props\.duration\)" ./src/react/resolve.ts | head -50

Repository: vargHQ/sdk

Length of output: 622


🏁 Script executed:

# find the function signature that contains line 650
rg -B 100 "duration: Number\(props\.duration\)" ./src/react/resolve.ts | grep -E "^export |^async |function |props:" | head -20

Repository: vargHQ/sdk

Length of output: 36


🏁 Script executed:

# get the full function signature starting from the beginning
head -n 650 ./src/react/resolve.ts | tail -n 100 | grep -E "async|function|props|duration" | head -30

Repository: vargHQ/sdk

Length of output: 258


🏁 Script executed:

# find function definition that contains line 650
ast-grep --pattern 'export function $_(props: $_) {
  $$$
  duration: Number(props.duration) || 5,
  $$$
}'

Repository: vargHQ/sdk

Length of output: 36


🏁 Script executed:

# get broader context to find the function signature
sed -n '500,650p' ./src/react/resolve.ts | grep -E "^export|^async|^function|^\s*\(props" | tail -5

Repository: vargHQ/sdk

Length of output: 96


🏁 Script executed:

# get the function signature
sed -n '500,650p' ./src/react/resolve.ts | head -n 150

Repository: vargHQ/sdk

Length of output: 4827


🏁 Script executed:

# check the generateVideoRaw function to understand duration expectations
rg "function generateVideoRaw|export.*generateVideoRaw" -A 10 ./src/react/resolve.ts

Repository: vargHQ/sdk

Length of output: 36


🏁 Script executed:

# find generateVideoRaw definition
rg "generateVideoRaw" . --type ts --type tsx | head -20

Repository: vargHQ/sdk

Length of output: 81


🏁 Script executed:

# find generateVideoRaw definition
rg "generateVideoRaw" . -g "*.ts" | head -20

Repository: vargHQ/sdk

Length of output: 468


🏁 Script executed:

# find and examine the generate-video file
find . -name "generate-video.ts" -path "*/ai-sdk/*" | head -5

Repository: vargHQ/sdk

Length of output: 84


🏁 Script executed:

# get the function signature and docs for generateVideo
head -n 150 ./src/ai-sdk/generate-video.ts

Repository: vargHQ/sdk

Length of output: 3198


🏁 Script executed:

# check if there are tests for duration handling
rg "duration" ./src/react/resolve.ts -B 2 -A 2 | grep -E "duration|test|describe" | head -20

Repository: vargHQ/sdk

Length of output: 1270


🏁 Script executed:

# look at tests to see if duration: 0 is used anywhere
rg "duration.*0" . -g "*.ts" | grep -E "test|duration.*:.*0" | head -15

Repository: vargHQ/sdk

Length of output: 1338


fix duration coercion that overwrites explicit 0 values

line 650 uses Number(props.duration) || 5, so passing 0 or "0" gets silently converted to 5. this loses the distinction between missing vs explicitly provided values.

suggested patch
+  const parsedDuration =
+    props.duration === null || props.duration === undefined
+      ? undefined
+      : Number(props.duration);
+
   const { video } = await generateVideo({
@@
-    duration: Number(props.duration) || 5,
+    duration: Number.isFinite(parsedDuration) ? parsedDuration : 5,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/react/resolve.ts` at line 650, The duration fallback currently uses
"Number(props.duration) || 5" which treats explicit 0 as falsy and overwrites
it; update the duration assignment in resolve.ts to first detect missing values
(null/undefined) and only then default to 5, otherwise coerce props.duration to
a Number and fallback to 5 if that coercion produces NaN/Infinity; reference the
duration property and props.duration so you change the expression that computes
duration (replace the current ||-based expression with a null/undefined check
plus a Number.isFinite check to preserve explicit 0).

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