Kuberwastaken/claurst · error · anyhow::Error

--dangerously-skip-permissions cannot be used with…

Error message

--dangerously-skip-permissions cannot be used with root/sudo privileges for security reasons

What it means

claurst deliberately refuses to start in permission-bypass mode (`--dangerously-skip-permissions`, which sets PermissionMode::BypassPermissions and lets the agent run arbitrary commands without approval) when the process is running as root or sudo on Unix. This mirrors the TypeScript implementation's guard: running an unrestricted agent with superuser privileges is considered too dangerous.

Solutions

  1. Run claurst as a non-root user (recommended): create/use a normal user account and rerun without sudo
  2. In Docker, add a `USER <nonroot>` directive or run with `docker run --user 1000:1000`
  3. If elevated filesystem access was the reason for sudo, grant the needed directories to the normal user instead of running the agent as root
  4. If you truly need bypass mode in a root container, re-exec as a non-root user inside the container (e.g. `su developer -c 'claurst --dangerously-skip-permissions ...'`); the guard itself is intentional and should not be bypassed as root

Example fix

// before: running bypass mode as root in a container
docker run -it image claurst --dangerously-skip-permissions "fix tests"
// -> bail: cannot be used with root/sudo privileges

// after: run as a non-root user
docker run -it --user 1000:1000 image claurst --dangerously-skip-permissions "fix tests"
Defensive patterns

Strategy: validation

Validate before calling

# Detect root before invoking bypass mode
if [ "$(id -u)" -eq 0 ]; then echo "refusing: --dangerously-skip-permissions as root"; exit 1; fi
exec claurst --dangerously-skip-permissions "$@"

Try / catch

# Wrap invocations so root is caught early with a clear message
if ! out=$(claurst --dangerously-skip-permissions --print "task" 2>&1); then
  case "$out" in *root/sudo*) echo "Run as a non-root user.";; esac
fi

Prevention

When it happens

Trigger: Launching `claurst --dangerously-skip-permissions` while the effective UID is 0 (running as root, via `sudo claurst ...`, or inside a container/CI job that defaults to root), on a Unix platform (the check is `#[cfg(unix)]`).

Common situations: Docker containers that run as root by default; CI pipelines executing as root; developers habitually using sudo for the CLI; WSL or VM shells logged in as root.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10). Data as JSON: /api/errors/a3114b8ff6f77aaf. Report an issue: GitHub.

Appendix: source

Thrown at src-rust/crates/cli/src/main.rs:545

    // --bare implies --no-claude-md: opening an untrusted repo in bare mode
    // must not load or inject AGENTS.md memory files.
    config.disable_claude_mds = cli.no_claude_md || cli.bare;
    if cli.bare {
        // Bare mode runs no event hooks. Drop any hooks resolved from
        // settings so no `run_hooks` call site has anything to execute.
        config.hooks.clear();
    }
    if let Some(sp) = cli.system_prompt.clone() {
        config.custom_system_prompt = Some(sp);
    }
    if let Some(asp) = cli.append_system_prompt.clone() {
        config.append_system_prompt = Some(asp);
    }
    if cli.dangerously_skip_permissions {
        // Mirror TS setup.ts: block bypass mode when running as root/sudo.
        #[cfg(unix)]
        if nix::unistd::Uid::effective().is_root() {
            anyhow::bail!(
                "--dangerously-skip-permissions cannot be used with root/sudo privileges for security reasons"
            );
        }
        config.permission_mode = PermissionMode::BypassPermissions;
    } else {
        config.permission_mode = cli.permission_mode.into();
    }
    config.additional_dirs = cli.add_dir.clone();
    if cli.no_auto_compact {
        config.auto_compact = false;
    }
    if cli.auto_commits {
        config.auto_commits = Some(true);
    }
    config.project_dir = Some(cwd.clone());
    if let Some(p) = &cli.provider {
        config.provider = Some(p.clone());
    }

View on GitHub (pinned to b0637c97ec)