{"record":{"id":"5ca9fbcd8cf2491c","repo":"pear-devs/pear-desktop","slug":"number-between-0-and-1-expected-as-volume","errorCode":null,"errorMessage":"Number between 0 and 1 expected as volume!","messagePattern":"Number between 0 and 1 expected as volume!","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/plugins/crossfade/fader.ts","lineNumber":25,"sourceCode":" * - requestAnimationFrame()\n * - ES6\n *\n * Does not depend on any third-party library.\n *\n * License: MIT\n *\n * Nick Schwarzenberg\n * v0.2.0, 07/2016\n */\n\n// Internal utility: check if value is a valid volume level and throw if not\nconst validateVolumeLevel = (value: number) => {\n  // Number between 0 and 1?\n  if (!Number.isNaN(value) && value >= 0 && value <= 1) {\n    // Yup, that's fine\n  } else {\n    // Abort and throw an exception\n    throw new TypeError('Number between 0 and 1 expected as volume!');\n  }\n};\n\ntype VolumeLogger = <Params extends unknown[]>(\n  message: string,\n  ...args: Params\n) => void;\ninterface VolumeFaderOptions {\n  /**\n   * logging `function(stuff, …)` for execution information (default: no logging)\n   */\n  logger?: VolumeLogger;\n  /**\n   * either 'linear', 'logarithmic' or a positive number in dB (default: logarithmic)\n   */\n  fadeScaling?: string | number;\n  /**\n   * media volume 0…1 to apply during setup (volume not touched by default)","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/pear-devs/pear-desktop/blob/1e2aac5706c870c93ed74ba8727ae8390d3b0fa5/src/plugins/crossfade/fader.ts#L7-L43","documentation":"The VolumeFader crossfade helper validates every volume level and throws a TypeError when the value is not a finite number in the inclusive range 0..1. HTMLMediaElement.volume only accepts 0..1, so the fader enforces that contract up front. It is thrown from the constructor (via options.initialVolume) and from fadeTo(targetVolume).","triggerScenarios":"Passing options.initialVolume outside 0..1 to `new VolumeFader(media, {initialVolume: 1.5})`, calling fadeTo(-0.1), fadeTo(2), or passing a string/NaN/undefined volume because of a missing argument or a bad computation (e.g. percentage not divided by 100).","commonSituations":"Storing volume as a 0-100 percentage and forgetting to divide by 100; reading volume from localStorage/settings and parsing it into NaN; defaults like `options.volume ?? 2`; passing dB values instead of linear amplitude.","solutions":["Normalize percentages: `fadeTo(userVolume / 100)`","Validate user settings before constructing: clamp with `Math.min(1, Math.max(0, Number(v)))` and check Number.isFinite","If loading volume from persistence, wrap parsing in try/catch and fall back to a sane default like 0.7","Enable strict TypeScript typing (volume: number in 0..1) or a branded type so bad values fail at compile time"],"exampleFix":"// before\nfader.fadeTo(volumePercent); // 0..100 -> throws\n\n// after\nfader.fadeTo(Math.min(1, Math.max(0, volumePercent / 100)));","handlingStrategy":"validation","validationCode":"const toVolume = (v: unknown): number => {\n  const n = Number(v);\n  if (!Number.isFinite(n)) return 0.7; // default\n  return Math.min(1, Math.max(0, n));\n};\n// use: fader.fadeTo(toVolume(userValue));","typeGuard":"const isValidVolume = (v: unknown): v is number =>\n  typeof v === 'number' && Number.isFinite(v) && v >= 0 && v <= 1;","tryCatchPattern":"try { fader.fadeTo(target); } catch (e) { if (e instanceof TypeError && /volume/.test(e.message)) { /* clamp and retry */ fader.fadeTo(0); } else throw e; }","preventionTips":["Never store volume as 0-100 in app state; normalize to 0..1 at the boundary","Clamp user input with Math.min/Math.max before passing","Persist volumes as numbers, parse with Number() and default on NaN"],"tags":["crossfade","volume","validation","typeerror","range"],"backgroundTag":"argument-out-of-range","analyzedSha":"1e2aac5706c870c93ed74ba8727ae8390d3b0fa5","analyzedAt":"2026-08-27T20:01:08.614Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}