nexu-io/open-design · error · SystemExit

Refusing to use dangerous output directory: {output_dir}. Ch

Error message

Refusing to use dangerous output directory: {output_dir}. Choose a dedicated generated-bundle directory instead.

What it means

Thrown by validate_output_dir() in prepare_chat_overlay_bundle.py when the requested --output-dir resolves to one of the dangerous targets: cwd, home, repo root, skill root, or the remotion-template directory. The bundle preparation step deletes and re-creates the output dir, so these locations would destroy user data or the skill itself.

Source

Thrown at skills/chat-motion-overlay/scripts/prepare_chat_overlay_bundle.py:57

def repo_root() -> Path:
    return skill_root().parent.parent


def bundle_marker_path(output_dir: Path) -> Path:
    return output_dir / BUNDLE_MARKER


def validate_output_dir(output_dir: Path, force: bool) -> None:
    dangerous_targets = {
        Path.cwd().resolve(),
        Path.home().resolve(),
        repo_root(),
        skill_root(),
        template_dir(),
    }
    if output_dir in dangerous_targets:
        raise SystemExit(
            f"Refusing to use dangerous output directory: {output_dir}. "
            "Choose a dedicated generated-bundle directory instead."
        )
    if output_dir.exists() and force and not bundle_marker_path(output_dir).exists():
        raise SystemExit(
            f"Refusing to overwrite unmanaged output directory: {output_dir}. "
            f"Only directories containing {BUNDLE_MARKER} can be replaced with --force."
        )


def copy_template(output_dir: Path, force: bool) -> None:
    validate_output_dir(output_dir, force)
    if output_dir.exists():
        if not force:
            raise SystemExit(f"Output directory already exists: {output_dir}. Use --force to overwrite.")
        shutil.rmtree(output_dir)
    shutil.copytree(template_dir(), output_dir)
    bundle_marker_path(output_dir).write_text("generated by chat-motion-overlay\n", encoding="utf-8")

View on GitHub (pinned to 5be4028344)

Solutions

  1. Point --output-dir at a dedicated generated-bundle directory such as ./.tmp/chat-overlay-bundle or a project-local build folder.
  2. If the path comes from a variable, resolve and log it before invoking the script to confirm it is not a protected location.
  3. Keep bundle output outside the skill and repo trees entirely (e.g. a dist/ or out/ folder).

Example fix

# before
python prepare_chat_overlay_bundle.py --output-dir . --force
# after
python prepare_chat_overlay_bundle.py --output-dir ./.tmp/chat-overlay-bundle --force
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
def assert_safe_output_dir(output_dir: Path, repo_root: Path, skill_root: Path) -> None:
    out = output_dir.resolve()
    dangerous = {Path.cwd().resolve(), Path.home().resolve(), repo_root.resolve(), skill_root.resolve(), (skill_root / "assets" / "remotion-template").resolve()}
    if out in dangerous:
        raise SystemExit(f"refusing dangerous output dir {out}")

Prevention

When it happens

Trigger: Run prepare_chat_overlay_bundle.py with --output-dir set to '.', '~', the repository root, the skill folder, or the assets/remotion-template folder (directly or via a symlink/relative path that resolves there). The run_test_matrix.py case 'invalid_force_dangerous_output_dir' passes the skill root to exercise this.

Common situations: Passing '.' or an empty-ish path expecting 'current dir is fine'; pointing output at the skill to 'overwrite in place'; a wrapper script that computes output_dir from a variable that happens to resolve to home.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/9163b8e5880d900b. Report an issue: GitHub.