can1357/oh-my-pi · error · RangeError

Audio gain must be a finite non-negative number

Error message

Audio gain must be a finite non-negative number

What it means

The streaming audio player validates gain before applying it: it must be a finite, non-negative number. NaN, Infinity, negative values, or non-numbers throw a RangeError from setGain, which is called both directly and from start().

Source

Thrown at packages/coding-agent/src/tts/streaming-player.ts:65

		}
	}

	/** Queues one mono `f32` PCM chunk without copying it in TypeScript. */
	write(pcm: Float32Array): void {
		if (this.#inputClosed || this.#stopped || pcm.length === 0) return;
		if (!this.#native && !this.#error) this.start(this.#sampleRate);
		const native = this.#native;
		if (!native) return;
		try {
			native.write(pcm);
		} catch (cause) {
			this.#failNative(native, cause);
		}
	}

	/** Applies gain at render time, including to samples already queued natively. */
	setGain(gain: number): void {
		if (!Number.isFinite(gain) || gain < 0) throw new RangeError("Audio gain must be a finite non-negative number");
		this.#gain = gain;
		const native = this.#native;
		if (!native) return;
		try {
			native.setGain(gain);
		} catch (cause) {
			this.#failNative(native, cause);
		}
	}

	/** Closes input and resolves after every queued sample reaches the speaker. */
	end(): Promise<void> {
		if (this.#ending) return this.#ending;
		if (this.#stopped) return Promise.resolve();
		this.#inputClosed = true;
		if (this.#error) {
			this.#stopped = true;
			return Promise.reject(this.#error);

View on GitHub (pinned to 9690622007)

Solutions

  1. Pass a finite number >= 0, e.g. Math.max(0, Number.isFinite(v) ? v : defaultGain)
  2. Coerce and clamp user/config input before calling setGain or start()
  3. Fix the upstream computation producing NaN/Infinity (check for undefined operands or divide-by-zero)

Example fix

// before
player.setGain(userVolume * multiplier); // may be NaN/negative
// after
const gain = Math.max(0, userVolume * multiplier);
player.setGain(Number.isFinite(gain) ? gain : 1);
Defensive patterns

Strategy: validation

Validate before calling

const g = Number(gain);
if (!Number.isFinite(g) || g < 0) throw new TypeError(`invalid gain: ${gain}`);
player.setGain(g);

Type guard

function isValidGain(v) {
  return typeof v === 'number' && Number.isFinite(v) && v >= 0;
}

Try / catch

try {
  player.setGain(gain);
} catch (err) {
  if (err instanceof RangeError && err.message.includes('gain')) {
    player.setGain(1); // safe default
  } else throw err;
}

Prevention

When it happens

Trigger: Calling player.setGain(NaN), setGain(-0.5), setGain(Infinity), or setGain(undefined as any); start() propagates the same error when it applies an initial invalid gain.

Common situations: A UI slider produces NaN from an empty input or division by zero; a config value is negative ('quiet down' attempts); a computation like volume * multiplier overflows to Infinity or yields NaN from undefined operands.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/cf2cf72e44ced42c. Report an issue: GitHub.