{"record":{"id":"4964008816193d02","repo":"calesthio/OpenMontage","slug":"detail","errorCode":null,"errorMessage":"{detail}","messagePattern":"\\{detail\\}","errorType":"exception","errorClass":"ToolCommandError","httpStatus":null,"severity":"error","filePath":"tools/base_tool.py","lineNumber":447,"sourceCode":"            return subprocess.run(\n                resolved_cmd,\n                capture_output=True,\n                text=True,\n                # Force UTF-8 decoding. The default uses the OS locale (cp1252 on\n                # Windows), which raises UnicodeDecodeError on a subprocess that\n                # emits Unicode/emoji (e.g. Remotion's progress output), killing the\n                # reader thread and potentially swallowing the real error text.\n                encoding=\"utf-8\",\n                errors=\"replace\",\n                timeout=timeout,\n                cwd=cwd,\n                check=True,\n            )\n        except subprocess.CalledProcessError as exc:\n            stderr = (exc.stderr or \"\").strip()\n            stdout = (exc.stdout or \"\").strip()\n            detail = stderr or stdout or str(exc)\n            raise ToolCommandError(\n                exc.returncode,\n                exc.cmd,\n                output=exc.output,\n                stderr=exc.stderr,\n                detail=detail,\n            ) from exc\n\n\nclass ToolCommandError(subprocess.CalledProcessError):\n    \"\"\"CalledProcessError with stderr/stdout surfaced in str(error).\"\"\"\n\n    def __init__(\n        self,\n        returncode: int,\n        cmd: list[str],\n        *,\n        output: Optional[str] = None,\n        stderr: Optional[str] = None,","sourceCodeStart":429,"sourceCodeEnd":465,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/base_tool.py#L429-L465","documentation":"Raised by BaseTool.run_command when a subprocess it launched exits non-zero: subprocess.run(..., check=True) raises CalledProcessError, which is wrapped into ToolCommandError carrying returncode, cmd, output, and stderr. The detail is stderr if present, else stdout, else str(exc) — so the message you see is the underlying command's own error text, not a library string. ToolCommandError subclasses subprocess.CalledProcessError, so standard attributes (returncode, cmd, stdout, stderr) are available for programmatic handling.","triggerScenarios":"Any tool shelling out to ffmpeg/ffprobe/node/CLI binaries with invalid arguments, unreadable input files, unsupported codecs, or write-permission failures on the output path. E.g. ffmpeg exiting 1 on a corrupt input surfaces its stderr here.","commonSituations":"Bad file paths or codec mismatches passed to ffmpeg; a CLI tool's version changing its flags; disk-full or permission-denied on output; non-UTF8 output already mitigated by errors='replace', so the real error text survives; command timeouts surface separately.","solutions":["Read e.stderr/e.stdout from the caught ToolCommandError — they contain the actual command diagnostics","Reproduce manually: run e.cmd in a shell with the same arguments to iterate quickly","Fix the concrete underlying issue (input file, codec, flags, permissions, disk space)","Pin or adapt to the external tool's version if flags changed; never retry blindly on deterministic argument errors"],"exampleFix":"# before\ntry:\n    tool.run_command([\"ffmpeg\", \"-i\", src, out])\nexcept ToolCommandError as e:\n    raise RuntimeError(f\"command failed: {e}\")  # loses diagnostics\n\n# after\ntry:\n    tool.run_command([\"ffmpeg\", \"-i\", src, out])\nexcept ToolCommandError as e:\n    log.error(\"cmd=%s rc=%s stderr=%s\", e.cmd, e.returncode, (e.stderr or \"\").strip())\n    raise","handlingStrategy":"try-catch","validationCode":"import shutil\nif not shutil.which(cmd[0]):\n    raise SystemExit(f\"command {cmd[0]} not installed\")\nfor f in input_files:\n    if not Path(f).is_file():\n        raise SystemExit(f\"input missing: {f}\")","typeGuard":null,"tryCatchPattern":"from tools.base_tool import ToolCommandError\ntry:\n    tool.run_command(cmd)\nexcept ToolCommandError as e:\n    log.error(\"cmd=%s rc=%s\\nstderr=%s\", e.cmd, e.returncode, (e.stderr or \"\").strip())\n    if e.returncode in (13,):  # deterministic permission error: do not retry\n        raise\n    if is_transient(e):  # e.g. network-flaky downloader\n        return tool.run_command(cmd)  # single retry\n    raise","preventionTips":["Always log e.stderr/e.returncode — the underlying command's diagnostics are attached","Reproduce the failing e.cmd manually before changing code","Guard against retrying deterministic failures (bad arguments, missing files); retry only transient ones","Check output directory permissions and disk space before long renders"],"tags":["subprocess","ffmpeg","cli","error-handling"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}