Whisper Keeps Repeating Itself: Fix Hallucinated Lines
Want to go deeper than this article?
Free account unlocks the first chapter of all 25 courses — RAG, agents, MCP, voice AI, MLOps, real GitHub repos.
Voice working locally? Build the whole pipeline. Whisper, TTS, and voice cloning wired into real projects — hands-on courses. First chapter free, no card.
Short answer: turn on the VAD filter and turn off previous-text conditioning. In faster-whisper that is vad_filter=True, condition_on_previous_text=False. The first stops silence ever reaching the model, which is where the phantom "Thank you for watching!" comes from. The second breaks the feedback loop that turns one repeated line into forty. Everything below is what to do when those two are not enough — and what each fix costs you in accuracy.
Parameter names and defaults on this page were read from the current faster-whisper source (latest release v1.2.1, 2025-10-31) and openai/whisper transcribe.py. They are not identical between the two projects, and that mismatch is itself a common cause of "I set the flag and nothing changed" — there is a translation table below.
The Two-Line Fix
These two lines resolve the majority of hallucination reports. Try them before you change models, re-encode audio, or read any further.
from faster_whisper import WhisperModel
model = WhisperModel("large-v3", device="cuda", compute_type="float16")
segments, info = model.transcribe(
"meeting.wav",
vad_filter=True, # default is False in WhisperModel.transcribe
condition_on_previous_text=False, # default is True
)
for s in segments:
print(f"[{s.start:.2f} -> {s.end:.2f}] {s.text}")
Two things in that snippet are worth stopping on.
vad_filter defaults to False in WhisperModel.transcribe() — but to True in BatchedInferencePipeline.transcribe(). Same library, same version, opposite default. We have watched people conclude that VAD "does nothing" because their benchmark script used the batched pipeline (where it was already on) and their production script used the plain model class (where it was not). Check which class your code calls.
condition_on_previous_text defaults to True in openai/whisper and in faster-whisper's WhisperModel.transcribe() — the batched pipeline is the exception, defaulting it to False. That default is the single design decision behind the classic 40-repeats transcript, and it exists for a good reason — cross-segment context genuinely improves proper nouns and jargon. It just fails catastrophically rather than gracefully.
Reading articles is good. Building is better.
Free account = the first chapter of all 25 courses, with a per-chapter AI tutor. No card.
Symptom 1: "Thank You for Watching" Over Silence
Cause: Whisper always emits text for a window, and silent windows have no answer, so the model falls back to the most likely thing in its training data — subtitle boilerplate.
The strings people paste into Google are consistent across every language and every project: "Thank you for watching!", "Subtitles by the Amara.org community", "Please subscribe", channel outros. These are not random. They are the highest-probability text for a 30-second window that contains no speech, learned from a training corpus full of subtitle files whose final lines look exactly like that.
The important consequence: you cannot fix this with a decoding parameter alone, because the problem is the input. Thresholds like no_speech_threshold (default 0.6) and log_prob_threshold (default -1.0) are meant to suppress this, and they help, but they are probabilistic filters applied after the model has already generated a confident-looking sentence. The reliable fix is to never send the silence.
segments, info = model.transcribe(
"lecture.wav",
vad_filter=True,
vad_parameters=dict(
threshold=0.5, # Silero speech probability cutoff
min_silence_duration_ms=2000, # library default
speech_pad_ms=400, # library default
),
)
faster-whisper runs Silero VAD (upgraded to Silero-VAD V6 in the v1.2.1 release) to find speech regions and hands the model only those. Silence never becomes a 30-second window, so there is nothing for the model to fill.
If you are transcribing long recordings with substantial dead air — lectures with pauses, security-camera audio, interview recordings with setup time at the front — this is the whole fix. See our faster-whisper guide for the install and model-size side, and local AI subtitles with Whisper if the output is destined for SRT.
Symptom 2: The Same Paragraph, Forty Times
Cause: condition_on_previous_text=True feeds the text Whisper just produced back in as the prompt for the next window. Once a repetition starts, the model is being told that repeating is what this recording sounds like.
This is why the failure has its distinctive shape: it does not produce forty scattered errors, it produces one error that then runs to the end of the file. The loop is self-reinforcing by construction.
segments, info = model.transcribe(
"interview.wav",
condition_on_previous_text=False,
)
If you would rather not lose context across the whole file, faster-whisper has a middle setting: prompt_reset_on_temperature, default 0.5. The prompt is kept while decoding is going well and dropped once the decoder has already fallen back past that temperature — that is, at the point where things are starting to go wrong anyway. It is a reasonable default and worth trying before you turn conditioning off entirely.
faster-whisper also exposes two sequence-level penalties that openai/whisper does not: repetition_penalty (default 1, i.e. off) and no_repeat_ngram_size (default 0, i.e. off). These are blunt instruments — a no_repeat_ngram_size of 3 will also block legitimate repeated phrases, and transcripts of real meetings contain plenty of those. Reach for them last, and only for audio where you know repetition is never genuine.
Symptom 3: Loops That Survive Both Fixes
Cause, most often: someone disabled the temperature fallback to make runs deterministic, and removed the guardrail that catches degenerate output.
Whisper's default temperature is not a single value. It is a fallback ladder — (0.0, 0.2, 0.4, 0.6, 0.8, 1.0) in openai/whisper, and the same list in faster-whisper. Decoding starts greedy at 0.0; if the result trips a quality check, it retries the window at a higher temperature. Two checks drive that retry:
| Check | Default | What trips it |
|---|---|---|
compression_ratio_threshold | 2.4 | The output gzip-compresses too well — the signature of repeated text |
log_prob_threshold (openai/whisper: logprob_threshold) | -1.0 | The model's own average confidence is too low |
no_speech_threshold | 0.6 | The no-speech token probability is high enough to call the window silent |
The compression-ratio check exists precisely to catch repetition loops: text that says the same thing forty times compresses far better than natural speech does. If you passed temperature=0 to make output reproducible, you disabled the retry that this check triggers. You get determinism and you keep the loop. Put the list back.
The second-line tool is hallucination_silence_threshold, which defaults to None (off) in both projects. openai/whisper's docstring is explicit about the catch: it applies "when word_timestamps is True", skipping silent periods longer than the threshold in seconds when a possible hallucination is detected. Set it without word timestamps and it does nothing — which is exactly why it has a reputation for being broken.
segments, info = model.transcribe(
"long_recording.wav",
vad_filter=True,
condition_on_previous_text=False,
word_timestamps=True, # REQUIRED for the next line to do anything
hallucination_silence_threshold=2.0,
temperature=[0.0, 0.2, 0.4, 0.6, 0.8, 1.0],
)
Word timestamps cost extra compute, so this is a fix to apply when you need it rather than by default. If you want word-level alignment anyway, WhisperX does that job properly with a separate alignment model.
Run this on your own machine and stop paying every month
Pay once and keep it. No renewal, no per-token bill, and nothing you feed it ever leaves your hardware.
Parameter Names by Engine
The names are not the same across projects, and a silently ignored keyword argument is the most common reason a "fix" appears not to work.
| What you want | openai/whisper | faster-whisper | whisper.cpp |
|---|---|---|---|
| Stop sending silence to the model | not built in | vad_filter=True, vad_parameters | --vad with --vad-model |
| Break the repetition feedback loop | condition_on_previous_text=False | condition_on_previous_text=False | — |
| Confidence floor | logprob_threshold (-1.0) | log_prob_threshold (-1.0) | — |
| Repetition guardrail | compression_ratio_threshold (2.4) | compression_ratio_threshold (2.4) | — |
| Silence detection threshold | no_speech_threshold (0.6) | no_speech_threshold (0.6) | — |
| Skip long silences on suspicion | hallucination_silence_threshold (None) | hallucination_silence_threshold (None) | — |
| Partial context reset | — | prompt_reset_on_temperature (0.5) | — |
| Token-level repetition penalty | — | repetition_penalty (1), no_repeat_ngram_size (0) | — |
Note logprob_threshold versus log_prob_threshold. One underscore. Both projects will accept a wrong keyword into **decode_options or reject it depending on the call path, and neither will tell you your intended fix did nothing.
Tuning the VAD (When the Default Clips Speech)
If VAD fixed the hallucinations but ate the first word of quiet sentences, adjust speech_pad_ms and threshold — in that order.
These are faster-whisper's VadOptions defaults, read from the library source:
| Option | Default | What it does |
|---|---|---|
threshold | 0.5 | Silero speech probability; chunks above this are treated as speech |
neg_threshold | None | Below this probability it is always silence — used to decide where speech ends |
min_speech_duration_ms | 0 | Speech chunks shorter than this are discarded |
max_speech_duration_s | inf | Longer chunks are split at the last long-enough silence |
min_silence_duration_ms | 2000 | How much silence must follow before a chunk is closed |
speech_pad_ms | 400 | Padding added to each side of every speech chunk |
Practical reading of that table:
- Clipped word onsets → raise
speech_pad_ms(600-800 is a reasonable next step). This is the setting that exists for exactly this problem. - Quiet or distant speakers dropped entirely → lower
thresholdtoward 0.3. You will let more noise through, which means more chances for the model to hallucinate on it — so lower it as little as you can get away with. - Music or applause being treated as speech → raise
thresholdtoward 0.6-0.7. Music is the hardest case for any VAD and you should expect to keep some manual cleanup on music-heavy files. - Segments running absurdly long → set
max_speech_duration_sto something finite, e.g. 30.
whisper.cpp and Parakeet
whisper.cpp has VAD built in now, and it is a flag, not a code change. The documentation names Silero-VAD as the supported model, downloaded with the bundled script:
./models/download-vad-model.sh silero-v6.2.0
./build/bin/whisper-cli \
-m models/ggml-base.en.bin \
-vm models/ggml-silero-v6.2.0.bin --vad \
-f samples/jfk.wav
The VAD tuning flags mirror the Python ones: --vad-threshold, --vad-min-speech-duration-ms, --vad-min-silence-duration-ms, --vad-max-speech-duration-s, --vad-speech-pad-ms, and --vad-samples-overlap (how much audio to extend from each speech segment into the next).
Parakeet is the architecture answer, not a parameter answer. NVIDIA's parakeet-tdt-0.6b-v3 is a 600M-parameter FastConformer-TDT model under CC-BY-4.0, covering 25 European languages, reporting a 6.34% average WER on the Open ASR Leaderboard, and able to transcribe up to 24 minutes in one pass with full attention (or roughly 3 hours with local attention) per its model card. Because it is a transducer rather than an autoregressive decoder conditioned on its own previous text, it does not have the specific feedback structure that produces Whisper's forty-repeats failure.
We want to be careful here, because the internet is not: the Parakeet model card makes no hallucination-resistance claim. "Different architecture, different failure modes" is the honest statement. It has its own weaknesses — the card reports a large relative degradation at -5dB SNR, and the language coverage is European, not universal. If you are considering the switch, our Parakeet vs Whisper comparison is the fuller picture.
Measure It on Your Own Audio
Do not re-run a 90-minute file to test a hypothesis. Build a 3-minute test clip that contains all four failure triggers, and iterate on that.
The four inputs that provoke Whisper hallucination reliably: a long stretch of pure silence, a music-only or applause passage, low-SNR speech (distant mic, air conditioning), and a short non-English clip padded out to a 30-second window. Concatenate them:
# 45s of silence, then your three real problem clips
ffmpeg -f lavfi -i anullsrc=r=16000:cl=mono -t 45 silence.wav
ffmpeg -i "concat:silence.wav|music.wav|quiet_speech.wav|foreign_clip.wav" \
-ar 16000 -ac 1 hallucination_test.wav
Then run one variable at a time and grep the output for the tell:
# count repeated lines — the fastest hallucination detector there is
sort transcript.txt | uniq -c | sort -rn | head -10
Any line with a count above 3 in a 3-minute clip is a loop, not speech. That single command is a better regression test than reading the transcript, and it runs in a second.
We are publishing the mechanism and the recipe rather than a table of our own WER numbers, because a hallucination rate measured on our test clip would tell you nothing useful about your microphone, your room and your language. Run the recipe; the numbers you get are the only ones that apply to you.
What Each Fix Costs
Every fix on this page trades something. Here is the honest ledger.
| Fix | What it costs |
|---|---|
vad_filter=True | Can clip quiet word onsets; speech_pad_ms mitigates. Adds a VAD pass to runtime |
condition_on_previous_text=False | Loses cross-segment context — worse on proper nouns, jargon and consistent spelling |
prompt_reset_on_temperature | Milder version of the above; only helps once decoding has already degraded |
| Keeping the temperature ladder | Slower and non-deterministic on hard windows — that is the price of the retry that saves you |
hallucination_silence_threshold | Requires word_timestamps=True, which costs extra compute |
no_repeat_ngram_size | Blocks genuinely repeated phrases too. Blunt |
| Switching to Parakeet | Different language coverage, different tooling, its own weak spots |
Our order of operations, every time: VAD first, conditioning second, restore the temperature ladder third, word-timestamp threshold fourth, engine change last.
If your problem is upstream of any of this — the model not loading, GPU not being used, out-of-memory during transcription — start at troubleshooting local AI instead. And if you are building this into an always-on assistant, the pipeline considerations are in our local voice assistant guide.
Sources
- faster-whisper source (
transcribe.py,vad.py) —TranscriptionOptionsfields,WhisperModelvsBatchedInferencePipelinedefaults,VadOptionsdefaults - faster-whisper v1.2.1 release notes — Silero-VAD V6 upgrade, batched-pipeline token fixes (2025-10-31)
- openai/whisper
transcribe.py— temperature ladder, threshold defaults,hallucination_silence_thresholddocstring - whisper.cpp README — VAD flags,
download-vad-model.sh, Silero model support - nvidia/parakeet-tdt-0.6b-v3 model card — parameters, licence, language coverage, WER and audio-length figures
FAQ
Voice working locally? Build the whole pipeline.
Whisper, TTS, and voice cloning wired into real projects — hands-on courses. First chapter free, no card.
Replace the speech-AI subscription
Local Speech Studio covers TTS, voice cloning and transcription end to end — including which licences actually let you sell what you make.
Liked this? 25 full AI courses are waiting.
From fundamentals to RAG, agents, MCP servers, voice AI, and production deployment with real GitHub repos. First chapter free, every course.
Build Real AI on Your Machine
RAG, agents, NLP, vision, and MLOps - chapters across 25 courses that take you from reading about AI to building AI.
Want structured AI education?
25 courses, 519+ chapters, from $9. Understand AI, don't just use it.
Continue Your Local AI Journey
- PILLARXTTS v2 (Coqui TTS): Free Local Voice Cloning, 17 Languages
- audio.cpp: Local TTS and Speech-to-Text, No Python
- Best Local TTS Models 2026: 8 Open-Source Voices Tested
- Build a $10K/Month AI Podcast: Whisper + Bark + Coqui TTS
- Build a Local Voice Assistant: Whisper + Ollama + Piper
- Chatterbox TTS Setup: Free ElevenLabs Killer (MIT, 2026)
- Coqui TTS Python Guide: pip install + XTTS API Examples
- Dub Videos Into Any Language Locally: pyVideoTrans + Whisper
- F5-TTS Setup Guide: Run Open-Source Voice Cloning Locally
- Faster-Whisper: Install and Run 4x Faster Speech-to-Text
Comments (0)
No comments yet. Be the first to share your thoughts!