{"record":{"id":"be2ba13a8bcad1ba","repo":"unslothai/unsloth","slug":"audio-must-be-max-minutes-unit-or-shorter","errorCode":null,"errorMessage":"Audio must be {max_minutes} {unit} or shorter.","messagePattern":"Audio must be (.+?) (.+?) or shorter\\.","errorType":"http","errorClass":"SttAudioTooLongError","httpStatus":413,"severity":"error","filePath":"studio/backend/core/inference/stt_sidecar.py","lineNumber":1100,"sourceCode":"    sample_count = 0\n    raw_buffer = io.BytesIO()\n    resampler = av.audio.resampler.AudioResampler(\n        format = \"s16\",\n        layout = \"mono\",\n        rate = _TARGET_SAMPLE_RATE,\n    )\n    # Group frames before resampling so short clips need one resampler call\n    # rather than one per codec frame.\n    fifo = av.audio.fifo.AudioFifo()\n\n    def write_frame(frame) -> None:\n        nonlocal sample_count\n        array = frame.to_ndarray()\n        sample_count += array.size\n        if sample_count > max_samples:\n            max_minutes = _MAX_AUDIO_SECONDS // 60\n            unit = \"minute\" if max_minutes == 1 else \"minutes\"\n            raise SttAudioTooLongError(f\"Audio must be {max_minutes} {unit} or shorter.\")\n        raw_buffer.write(array)\n\n    try:\n        with av.open(io.BytesIO(audio), mode = \"r\", metadata_errors = \"ignore\") as container:\n            if not container.streams.audio:\n                raise SttAudioDecodeError(\"Could not decode the audio.\")\n            frames = iter(container.decode(audio = 0))\n            while True:\n                try:\n                    frame = next(frames)\n                except StopIteration:\n                    break\n                except InvalidDataError:\n                    # Skip a corrupt frame rather than fail the whole transcription.\n                    continue\n                if cancel_event is not None and cancel_event.is_set():\n                    raise SttTranscriptionCancelledError(\"Transcription cancelled.\")\n                frame.pts = None","sourceCodeStart":1082,"sourceCodeEnd":1118,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/inference/stt_sidecar.py#L1082-L1118","documentation":"Raised during frame-by-frame decoding when the cumulative resampled sample count exceeds _MAX_AUDIO_SECONDS * _TARGET_SAMPLE_RATE, i.e. the clip is longer than the hard cap (shown in whole minutes). The cap is enforced as frames arrive so long uploads are rejected early rather than after a full decode.","triggerScenarios":"Uploading audio longer than the cap (e.g. >10 min at 16 kHz if _MAX_AUDIO_SECONDS is 600) to transcribe(); the count is checked inside write_frame after each resampled batch, so any decode whose cumulative samples exceed max_samples raises.","commonSituations":"Users dictating or uploading long recordings (meetings, podcasts); clients that concatenate clips before sending; changed constants after an upgrade lowering the cap.","solutions":["Trim or split the audio client-side into segments within the cap (the engine windows at 30s internally, but the total input cap still applies).","If self-hosting and longer input is acceptable, raise _MAX_AUDIO_SECONDS consciously — it exists to bound memory/CPU of decode.","Show the limit in the upload UI so users pre-split long files."],"exampleFix":"// before\nstt.transcribe(hour_long_mp3);  // SttAudioTooLongError\n// after\nfor chunk in split_audio(hour_long_mp3, max_seconds=(_MAX_AUDIO_SECONDS - 5)):\n    results.append(stt.transcribe(chunk))","handlingStrategy":"validation","validationCode":"MAX_S = _MAX_AUDIO_SECONDS  # import from stt_sidecar\nif estimate_duration_seconds(audio_path) > MAX_S - 5:  # small safety margin\n    split_or_reject(audio_path)","typeGuard":null,"tryCatchPattern":"try:\n    text = stt.transcribe(audio)\nexcept SttAudioTooLongError as e:\n    show_user(str(e)); suggest_splitting()","preventionTips":["Enforce a client-side duration limit matching _MAX_AUDIO_SECONDS","Cap recorder recording time in the UI","Split long media into per-chunk transcribe() calls and join texts"],"tags":["stt","audio","limit","validation","duration"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}