fix(dubbing): retain actionable native failure diagnostics

This commit is contained in:
Palash Debnath
2026-09-17 12:37:43 +05:30
parent 18c543484b
commit 9482788898
4 changed files with 46 additions and 2 deletions
+4
View File
@@ -16,6 +16,10 @@ the frozen-backend fallback mirror it for their toolchains.
- Handle missing Electron signing credentials and retry packaging fixes without moving release tags (#2157)
### Fixed
- Show scrubbed native error tails and exit codes for failed dubbing extraction (#2167)
## [0.5.3] — 2026-09-17
**Highlights**
+13 -2
View File
@@ -64,6 +64,17 @@ from core.logging_utils import log_safe
logger = logging.getLogger("omnivoice.dub_pipeline")
def _media_process_error(tool: str, returncode: int, stderr: bytes) -> str:
"""Keep the actionable end of native diagnostics without leaking paths."""
from core.scrub import scrub_text
detail = scrub_text(stderr.decode(errors="replace")).strip()
tail = detail[-2000:]
if len(detail) > 2000:
tail = "" + tail
return f"{tool} exited with code {returncode}" + (f": {tail}" if tail else ". No diagnostic output.")
# ── Module-level state ──────────────────────────────────────────────────────
# These used to live in dub_core.py. The router now re-exports them for
# backward compat during the transition.
@@ -1326,7 +1337,7 @@ async def ingest_pipeline(
"-ar", "16000", "-ac", "1", audio_path, "-y",
])
if p.returncode != 0:
msg = (stderr.decode(errors="replace") or f"ffmpeg returned exit code {p.returncode}").strip()[:500]
msg = _media_process_error("FFmpeg", p.returncode, stderr)
raise Exception(msg)
# Second, FULL-QUALITY extraction for source separation. audio.wav
# is deliberately 16 kHz mono — that's what ASR wants — but Demucs
@@ -1476,7 +1487,7 @@ async def ingest_pipeline(
elif evt[0] == "done":
rc, stderr_full = evt[1], evt[2]
if rc != 0:
raise Exception(stderr_full.decode(errors="replace")[:500])
raise Exception(_media_process_error("Demucs", rc, stderr_full))
# Stems land under the INPUT's basename ("audio_hq" when the
# full-quality extraction succeeded, "audio" on its fallback).
demucs_out = os.path.join(
+4
View File
@@ -1148,3 +1148,7 @@ remove the app binary itself are in
[docs/install/uninstall.md](uninstall.md).
**Linked issue:** [#1089](https://github.com/debpalash/VoiceStudio/issues/1089)
### Dubbing extraction fails
Extraction errors show the FFmpeg exit code and the end of its diagnostics, with private paths scrubbed. Use the final error line to distinguish missing audio streams, unsupported inputs, permissions, or disk errors. A version banner alone does not identify the cause; include the final diagnostic and source format when reporting a failure.
+25
View File
@@ -0,0 +1,25 @@
import json
from types import SimpleNamespace
import pytest
from services import dub_pipeline
@pytest.mark.asyncio
async def test_extract_error_preserves_failure_after_long_banner(tmp_path, monkeypatch):
stderr = ("ffmpeg version configuration " * 100 + "\n/home/private/media/secret.mp4: No audio stream found").encode()
async def run_proc(args):
return SimpleNamespace(returncode=1), b"", stderr
monkeypatch.setattr(dub_pipeline, "find_ffmpeg", lambda: "ffmpeg")
monkeypatch.setattr(dub_pipeline, "run_proc_factory", lambda job: run_proc)
events = [event async for event in dub_pipeline.ingest_pipeline(
"diagnostic", str(tmp_path), {"kind": "upload", "path": str(tmp_path / "input.mp4")},
)]
output = "\n".join(events)
assert "No audio stream found" in output
assert "code 1" in output
assert "/home/private/" not in output
def test_empty_native_diagnostic_retains_exit_code():
assert "code 7" in dub_pipeline._media_process_error("FFmpeg", 7, b"")