ChatGPTNextWeb/NextChat · error · Error
Recording not started
Error message
Recording not started
What it means
Thrown at app/lib/audio.ts:88 inside AudioHandler.stopRecording() when any of workletNode, source, or stream is null — i.e. startRecording() never completed successfully. stopRecording assumes the recording graph is wired; calling it before startRecording (or after a failed startRecording that threw and left the fields null) violates that precondition.
Source
Thrown at app/lib/audio.ts:88
// @ts-ignore
this.recordBuffer.push.apply(this.recordBuffer, int16Data);
}
};
this.source.connect(this.workletNode);
this.source.connect(this.mergeNode, 0, 0);
this.workletNode.connect(this.context.destination);
this.workletNode.port.postMessage({ command: "START_RECORDING" });
} catch (error) {
console.error("Error starting recording:", error);
throw error;
}
}
stopRecording() {
if (!this.workletNode || !this.source || !this.stream) {
throw new Error("Recording not started");
}
this.workletNode.port.postMessage({ command: "STOP_RECORDING" });
this.workletNode.disconnect();
this.source.disconnect();
this.stream.getTracks().forEach((track) => track.stop());
}
startStreamingPlayback() {
this.isPlaying = true;
this.nextPlayTime = this.context.currentTime;
}
stopStreamingPlayback() {
this.isPlaying = false;
this.playbackQueue.forEach((source) => source.stop());
this.playbackQueue = [];
this.playBuffer = [];View on GitHub (pinned to defdcdb55d)
Solutions
- Guard stopRecording with an early return when not recording instead of throwing.
- Track an explicit isRecording boolean and only call stopRecording when true.
- Ensure startRecording's error is surfaced (not swallowed) so the UI stays in sync and stop is not invoked.
- Disable the stop button until startRecording resolves successfully.
Example fix
// before
stopRecording() {
if (!this.workletNode || !this.source || !this.stream) {
throw new Error("Recording not started");
}
// ...
}
// after
stopRecording() {
if (!this.workletNode || !this.source || !this.stream) {
return; // nothing to stop, no-op
}
this.workletNode.port.postMessage({ command: "STOP_RECORDING" });
this.workletNode.disconnect();
this.source.disconnect();
this.stream.getTracks().forEach((track) => track.stop());
this.workletNode = null;
this.source = null;
this.stream = null;
} Defensive patterns
Strategy: validation
Validate before calling
class AudioHandler {
private isRecording = false;
async startRecording(onChunk: (c: Uint8Array) => void) {
// ... existing setup ...
this.isRecording = true;
}
canStop(): boolean {
return this.isRecording && !!this.workletNode && !!this.source && !!this.stream;
}
}
if (handler.canStop()) {
handler.stopRecording();
} Type guard
function isRecordingGraphReady(h: AudioHandler): boolean {
// Access via public getter if added; otherwise guard from the caller using an isRecording flag
return (h as unknown as { workletNode: unknown; source: unknown; stream: unknown })
.workletNode != null;
} Try / catch
try {
handler.stopRecording();
} catch (e) {
if (e instanceof Error && /not started/.test(e.message)) {
// no recording in progress — safe to ignore
} else {
throw e;
}
} Prevention
- Track an explicit isRecording flag and gate stopRecording on it.
- Surface startRecording errors to the UI so stop is never called on a failed start.
- Make stopRecording idempotent (no-op when not recording) instead of throwing.
- Null out workletNode/source/stream after stopping so a second stop is a clean no-op.
When it happens
Trigger: Calling stopRecording() before startRecording(); startRecording() threw inside getUserMedia/createMediaStreamSource/addModule (mic permission denied, worklet module 404, AudioContext suspended) leaving workletNode null; calling stopRecording() twice (the second call sees fields nulled after disconnect).
Common situations: User clicks stop before clicking record; mic permission was denied so startRecording failed silently in a caller that swallowed the error; audio-processor.js failed to load; AudioContext is suspended on iOS/Safari and startRecording did not resume; double-stop from a race in the UI.
Related errors
AI-assisted analysis of ChatGPTNextWeb/NextChat@defdcdb55d (2026-08-12).
Data as JSON: /api/errors/3cd5130f1391f0db.
Report an issue: GitHub.