Errors & diagnostics
Standard ASR follows "explicit > implicit": when something goes wrong, you get a specific exception with machine-readable context -- never silent degradation.
Exception hierarchy
Every domain exception inherits from StandardASRError, so a single
except StandardASRError catches every domain error the runtime raises.
Plain caller misuse and pydantic validation sit outside the hierarchy --
see the section after the table.
StandardASRError
+-- StructuredError (adds .param / .hint / .details)
| +-- ConfigError invalid config (bad language, bad value, ...)
| | +-- ConfigurationRequiredError required config ABSENT (for example, credential not set)
| +-- TranscriptionError engine failed during transcription
| +-- UnsupportedFeatureError unsupported feature (always) or parameter (strict mode)
| +-- InvalidProviderParamError wrong engine's provider_params passed
+-- AudioProcessingError audio decode / size / sample-rate failure
| +-- IncompatibleAudioInputError no conversion path exists
| | +-- UnsafeAudioUrlError AudioUrl failed the SSRF policy (non-HTTPS, private IP)
| +-- FFmpegNotFoundError FFmpeg needed but not on PATH
| +-- FFprobeNotFoundError FFprobe needed but not on PATH
+-- EngineContractError engine broke the protocol contract (async transcribe, bad declaration)
+-- SubtitleRenderingError to_srt/to_vtt: segments lack measured timing (choose a policy)
+-- StreamClosedError audio delivered to a closed session
+-- InvalidSessionUseError session driven incorrectly (for example, mixing feed() with send_audio())
+-- DiscoveryError plugin discovery problem
+-- EntrypointValidationError bad entry-point name or metadata
+-- FactoryLoadError entry point failed to import / not callableWhen each exception fires
| Exception | When | Typical cause |
|---|---|---|
ConfigError | create(), transcribe(), or start_transcription() | Invalid config value — bad pydantic validation, or a default_language that is malformed / not selectable. Fixable by whoever supplies the config. |
ConfigurationRequiredError | create() / from_env(), or lazily at the first transcribe() / session when the engine defers its credential check | A required field (for example, an API key) is absent from both explicit config and the environment — set it and retry; compliance treats this as a skip, not a failure. |
TranscriptionError | transcribe() / start_transcription() | Engine crashed or returned an invalid result. |
UnsupportedFeatureError | start_transcription() always for an unsupported streaming axis or wire format; transcribe() / start_transcription() in strict mode for an unsupported parameter | Requested streaming on a batch-only engine, or word timestamps (strict) on an engine that does not support them. |
InvalidProviderParamError | transcribe() or start_transcription() | Passed faster-whisper's provider_params to an OpenAI engine (swap-safety). |
AudioProcessingError | transcribe() / start_transcription(audio=...) | Corrupt audio file, missing sample rate, unsupported format without [audio] extra. |
IncompatibleAudioInputError | transcribe() / start_transcription(audio=...) | Passed a URL to an engine that only accepts arrays, and no conversion path exists. |
UnsafeAudioUrlError | transcribe() / start_transcription(audio=...) | An AudioUrl failed the SSRF policy (non-HTTPS, private IP, etc.). |
SubtitleRenderingError | to_srt() / to_vtt() | A segment cannot render as a visible cue — no measured start/end span, or a span that quantizes to zero milliseconds on the output grid (players silently drop T --> T cues) — and on_unrenderable is the default "error". Choose the loss explicitly: "omit" (renderable cues only) or "collapse" (one whole-text cue). Carries .unrenderable / .total counts. |
EngineContractError | any synchronous protocol member, or transcribe() / start_transcription() on a language-declaration defect | The engine returned an awaitable (an async def implementation) or a wrong-typed value from a sync member (transcribe(), start_transcription(), supports(), and so on), declared a language axis without a default_language (IC.6), or declared a malformed selectable/detectable tag. An engine/plugin bug — report it to the engine's author; nothing in your code is wrong. |
StreamClosedError | session.send_audio(); SyncSession audio calls and iteration after the bridge tore down | Sending audio manually after end_audio() or after the session delivered a terminal event. The async session's feed() never raises it: a managed source's post-terminal chunks are discarded by design. The sync bridge is stricter: once it tore down (its with block exited, or a lifecycle call timed out), feed(), send_audio(), end_audio(), and iteration raise it -- there is no loop left to discard into. result() and diagnostics() still work. |
InvalidSessionUseError | session.feed() / session.send_audio() / iterating the session | Driving a still-live session incorrectly: mixing managed feed() with manual send_audio()/end_audio(), calling feed() twice, or iterating the event stream twice. The session is NOT closed — fix the calling code; do not rebuild the session. |
EntrypointValidationError | discover_models() (strict mode); registry.spec() / create() on an unknown or malformed key | A plugin's entry-point name is malformed, or a lookup key does not resolve. |
FactoryLoadError | registry.engine_class() / registry.create() | Plugin's entry point cannot be imported or the factory is misconfigured. |
What StandardASRError does not catch
Building a model is pydantic's job, not the runtime's. A malformed field raises
pydantic.ValidationError, which is a ValueError and not a
StandardASRError:
RuntimeParams(language="english") # ValidationError: not a BCP-47 tag
RuntimeParams(candidate_languages=["auto"])Plain caller misuse raises a built-in the same way: ValueError for a bad
value (passing both audio and audio_format to start_transcription()),
TypeError for a wrong type (an unsupported input type to transcribe()).
Catch the domain errors and the value mistakes together:
except (StandardASRError, ValueError): # ValidationError is a ValueError
...A TypeError stays outside both families on purpose: a wrong input type is a
code bug to fix, not a state to handle. The sync bridge's no-hang contract can
also raise the built-in TimeoutError for a hung engine.
Structured error context
StructuredError subclasses carry machine-readable fields:
try:
engine.transcribe("audio.wav", RuntimeParams(word_timestamps="word"))
except UnsupportedFeatureError as exc:
print(exc.param) # "word_timestamps" — the offending parameter
print(exc.mode) # "batch" — where the rejection happened
print(exc.hint) # actionable guidance, or None
try:
registry.create("acme/model")
except ConfigError as exc:
print(exc.param) # the offending field, if a single one is implicated
print(exc.details) # sanitized [{"type", "loc", "msg"}, ...] entriesThese fields let you build programmatic error handling (for example, fall back to another
engine when a feature is unsupported) without parsing message strings. Every
StructuredError also carries .details, populated where structured context
exists — ConfigError, for example, puts the sanitized pydantic validation
entries there (UnsupportedFeatureError leaves it None).
Diagnostics (non-fatal)
Not every problem is an exception. In best_effort mode, unsupported parameters
are dropped with a structured Diagnostic instead of raising:
result = engine.transcribe("audio.wav", RuntimeParams(word_timestamps="word"))
for diag in result.diagnostics:
print(diag.code, diag.message)
# unsupported_parameter_ignored Ignored unsupported parameter 'word_timestamps' in batch mode (capability 'batch.word_timestamps' not supported).Diagnostics surface:
- Parameter-gating decisions (dropped features, truncated prompts).
- Audio conversion steps (lossy resampling, format changes).
- Engine-authored messages during streaming (
session.diagnostics()).
The code field is a stable, machine-readable identifier; the message is
human-readable. Applications should key on code for programmatic handling.
Further reading
- API Reference: exceptions -- full type signatures and docstrings.
- Specification -- the normative error contract.