nexu-io/open-design · error · SystemExit

Refusing to overwrite unmanaged output directory: {output_di

Error message

Refusing to overwrite unmanaged output directory: {output_dir}. Only directories containing {BUNDLE_MARKER} can be replaced with --force.

What it means

Thrown by validate_output_dir() when --force is passed and the output dir already exists, but it does not contain the BUNDLE_MARKER file (.chat-motion-overlay-bundle). The marker is the trust signal that the directory was created by this tool; without it --force refuses to delete the tree to avoid wiping unrelated content.

Source

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

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")


def write_chat_spec_ts(spec: dict, output_dir: Path) -> None:
    target = output_dir / "src" / "chatSpec.ts"
    content = "export const chatSpec = " + json.dumps(spec, ensure_ascii=False, indent=2) + " as const;\n"

View on GitHub (pinned to 5be4028344)

Solutions

  1. Point --output-dir at a fresh dedicated directory this tool can own end-to-end.
  2. If the existing directory is safe to delete, remove it manually first (rm -rf) then run without --force, so the tool creates and marks it.
  3. If you are sure the directory is tool-managed but lost its marker, create an empty .chat-motion-overlay-bundle file inside it before re-running with --force.

Example fix

# before
python prepare_chat_overlay_bundle.py --output-dir ./existing-build --force  # no marker inside
# after
rm -rf ./existing-build && python prepare_chat_overlay_bundle.py --output-dir ./existing-build
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
MARKER = ".chat-motion-overlay-bundle"
def assert_managed_or_empty(output_dir: Path, force: bool) -> None:
    if output_dir.exists() and force and not (output_dir / MARKER).exists():
        raise SystemExit(f"{output_dir} is not tool-managed (no {MARKER}); remove it manually first")

Prevention

When it happens

Trigger: Run prepare_chat_overlay_bundle.py --output-dir <existing dir> --force where <existing dir> was created by something else (or by this tool before markers existed) and lacks the .chat-motion-overlay-bundle file.

Common situations: Reusing a generic build/dist folder that predates the marker; manually creating the output directory; pointing at a directory another generator owns.

Related errors


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