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

  1. Guard stopRecording with an early return when not recording instead of throwing.
  2. Track an explicit isRecording boolean and only call stopRecording when true.
  3. Ensure startRecording's error is surfaced (not swallowed) so the UI stays in sync and stop is not invoked.
  4. 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

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.