{"record":{"id":"047f2c3b10db4551","repo":"remotion-dev/remotion","slug":"cannot-append-audio-after-the-time-stretcher-was-f","errorCode":null,"errorMessage":"Cannot append audio after the time stretcher was finalized.","messagePattern":"Cannot append audio after the time stretcher was finalized\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/media/src/audio/pitch-shift.ts","lineNumber":129,"sourceCode":"\t\tsampleRate: number;\n\t\tfactor: number;\n\t}) {\n\t\tthis.numberOfChannels = numberOfChannels;\n\t\tthis.factor = factor;\n\t\tthis.hopSize = Math.max(\n\t\t\t32,\n\t\t\tMath.round((REFERENCE_HOP_SIZE * sampleRate) / REFERENCE_SAMPLE_RATE),\n\t\t);\n\t\tthis.windowSize = this.hopSize * 2;\n\t\tthis.searchRadius = this.hopSize;\n\t\tthis.analysisHop = this.hopSize / factor;\n\t\tthis.input = makePlanarAudio(numberOfChannels, 65_536);\n\t\tthis.output = makePlanarAudio(numberOfChannels, 65_536);\n\t}\n\n\tpublic append(audio: PlanarAudio) {\n\t\tif (this.finalized) {\n\t\t\tthrow new Error(\n\t\t\t\t'Cannot append audio after the time stretcher was finalized.',\n\t\t\t);\n\t\t}\n\n\t\tconst {length} = audio[0];\n\t\tthis.input = ensurePlanarCapacity({\n\t\t\tbuffers: this.input,\n\t\t\trequiredLength: this.inputLength + length,\n\t\t});\n\n\t\tfor (let channel = 0; channel < this.numberOfChannels; channel++) {\n\t\t\tthis.input[channel].set(audio[channel], this.inputLength);\n\t\t}\n\n\t\tthis.inputLength += length;\n\t\tthis.totalInputFrames += length;\n\t\tthis.process();\n\t\treturn this.drainFinalizedOutput();","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/remotion-dev/remotion/blob/a6a7485a9aeb04219510fbe4874f8941486424df/packages/media/src/audio/pitch-shift.ts#L111-L147","documentation":"StreamingPitchShifter buffers input audio and only releases it on finalize(). Once finalize() has run, the internal state is drained and the instance refuses further input by throwing this error from append().","triggerScenarios":"Calling shifter.append(planarAudio) after shifter.finalize() has already been called on the same StreamingPitchShifter instance.","commonSituations":"Reusing a cached shifter across segments or files without creating a new one; calling finalize on end-of-stream and then appending late buffers; a generator loop that finalizes and continues feeding the same instance.","solutions":["Create a new StreamingPitchShifter for audio appended after finalize","Reorder logic so all append calls happen before finalize","Track finalized state in the caller and skip/reset instead of appending","For a new segment, instantiate a fresh shifter (as pitchShiftAudioIterator does on segment boundaries)"],"exampleFix":"// before\nconst out1 = shifter.append(a); shifter.finalize(); const out2 = shifter.append(b);\n// after\nconst out1 = shifter.append(a); shifter.finalize();\nconst shifter2 = new StreamingPitchShifter({numberOfChannels, sampleRate, toneFrequency});\nconst out2 = shifter2.append(b);","handlingStrategy":"validation","validationCode":"if (shifter.finalized) {\n  shifter = new StreamingPitchShifter({numberOfChannels, sampleRate, toneFrequency});\n}","typeGuard":"const canAppend = (s: StreamingPitchShifter): boolean => !s.finalized;","tryCatchPattern":"try {\n  shifter.append(audio);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('finalized')) {\n    shifter = new StreamingPitchShifter({numberOfChannels, sampleRate, toneFrequency});\n    shifter.append(audio);\n  } else throw e;\n}","preventionTips":["Treat a shifter as single-use: append-then-finalize, then discard","Guard cleanup/finally paths from double finalization","Track finalized state explicitly in streaming loops","Create a new shifter per segment instead of reusing instances"],"tags":["audio","pitch-shift","state-machine","media"],"backgroundTag":"use-after-finalize","analyzedSha":"a6a7485a9aeb04219510fbe4874f8941486424df","analyzedAt":"2026-09-02T16:25:19.997Z","contentChangedAt":"2026-09-02T16:25:19.997Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}