Skip to content

fix(edit-modal): Listening Length throws "trim is not a function" on every keystroke#709

Open
kevinheneveld wants to merge 1 commit into
Listenarrs:canaryfrom
kevinheneveld:fix/edit-modal-runtime-number-coercion
Open

fix(edit-modal): Listening Length throws "trim is not a function" on every keystroke#709
kevinheneveld wants to merge 1 commit into
Listenarrs:canaryfrom
kevinheneveld:fix/edit-modal-runtime-number-coercion

Conversation

@kevinheneveld

Copy link
Copy Markdown
Contributor

Problem

Editing Listening Length (minutes) in the audiobook edit modal throws on every keystroke. Each digit produces an "Unexpected Error — Something went wrong. Please refresh the page." toast, and after a few keystrokes the modal tears down.

Root cause

The field is <input type="number" v-model="formData.runtime">. Vue's v-model coerces a type="number" input to a JS numbervModelText casts whenever el.type === 'number', even without the .number modifier. So formData.runtime holds a number at runtime, despite being typed string.

normalizeNumericInput then runs:

return (value || '').trim()

Number.prototype has no .trim(), so this throws TypeError: (value || "").trim is not a function. It's invoked from the dirty-check (hasChanges) which re-evaluates on every keystroke. Vue's global errorHandler catches it (hence the toast rather than a console error), and the repeated failure unmounts the modal.

An empty field is '' (a genuine string), which is why it only surfaces once a digit is typed.

Fix

Harden normalizeNumericInput / parseRuntimeInput to accept string | number and String()-coerce before trimming:

function normalizeNumericInput(value: string | number | null | undefined): string {
  return (value == null ? '' : String(value)).trim()
}

Verification

Reproduced in a real browser by hooking the running app's errorHandler to capture the swallowed stack (TypeError: (e || "").trim is not a function), confirmed every keystroke threw and the 3rd closed the modal. After the fix: typing 452 leaves the modal open with zero error toasts and the field value intact. vue-tsc passes.

🤖 Generated with Claude Code

…every keystroke

The Listening Length field is `<input type="number" v-model="formData.runtime">`.
Vue's v-model coerces a `type="number"` input to a JS number (vModelText casts
whenever `el.type === 'number'`, even without the `.number` modifier), so
`formData.runtime` holds a number at runtime despite its declared string type.

`normalizeNumericInput` then ran `(value || '').trim()` on that number, and
`Number.prototype` has no `trim()`, throwing a `TypeError` on every keystroke.
Vue's global errorHandler caught each one (surfacing an "Unexpected Error" toast
per keystroke) and the accumulating failure tore the edit modal down. An empty
field is `''` (a real string), so it only manifested once a digit was typed.

Harden `normalizeNumericInput`/`parseRuntimeInput` to accept `string | number`
and `String()`-coerce before trimming.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kevinheneveld kevinheneveld requested a review from a team June 28, 2026 17:30
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