windmill-labs/windmill · error

Invalid path.

Error message

Invalid path.

What it means

define_nsjail_mount builds an nsjail mount spec by stripping the job_dir prefix off a file path inside the job directory. If the path does not actually live under job_dir, strip_prefix returns None and the `?` surfaces this generic anyhow error. It indicates a path-escape / miscomputed path, not user input directly.

Source

Thrown at backend/windmill-worker/src/ansible_executor.rs:2226

    ret
}

fn define_nsjail_mount(job_dir: &str, path: &PathBuf) -> anyhow::Result<String> {
    Ok(format!(
        r#"
mount {{
    src: "{0}/{1}"
    dst: "/tmp/{1}"
    is_bind: true
    rw: false
    mandatory: false
}}
        "#,
        job_dir,
        path.strip_prefix(job_dir)?
            .to_str()
            .ok_or(anyhow!("Invalid path."))?
    ))
}

async fn create_file_resources(
    job_id: &Uuid,
    w_id: &str,
    job_dir: &str,
    args: Option<&HashMap<String, Box<RawValue>>>,
    r: &AnsibleRequirements,
    client: &AuthedClient,
    conn: &Connection,
) -> error::Result<Vec<String>> {
    let mut logs = String::new();
    let mut nsjail_mounts: Vec<String> = vec![];

    for inventory in &r.inventories {
        let content;
        if let Some(resource_path) = &inventory.pinned_resource {

View on GitHub (pinned to e474e8803c)

Solutions

  1. Inspect the inventory/file resource `name` for path traversal (`..`, leading `/`) and use a plain relative filename.
  2. Check the error's source path: confirm job_dir is the same absolute prefix used when writing the file.
  3. If hit after an internal refactor, verify write_file_at_user_defined_location still returns paths rooted at job_dir.
  4. Report as a bug if the name looks normal — it likely means the mount path computation broke.

Example fix

// before: escaping name
inventory: { name: "../../../etc/prod" }
// after
inventory: { name: "prod_inventory" }
Defensive patterns

Strategy: validation

Validate before calling

fn is_safe_name(name: &str) -> bool {
    !name.is_empty()
        && !name.contains("..")
        && !name.starts_with('/')
        && name.chars().all(|c| c.is_alphanumeric() || matches!(c, '-' | '_' | '.'))
}

Type guard

fn safe_rel_path(job_dir: &Path, p: &Path) -> Option<PathBuf> {
    p.strip_prefix(job_dir).ok().map(|r| r.to_path_buf())
}

Prevention

When it happens

Trigger: write_file_at_user_defined_location (or a later mount definition in create_file_resources) returned a validated path that is not under job_dir, so `path.strip_prefix(job_dir)?` fails in define_nsjail_mount, called from create_file_resources.

Common situations: A file resource or inventory `name` containing `..` or absolute-path components escaping the job dir; a change in how job_dir is joined (trailing slash / relative vs absolute) making strip_prefix mismatch; symlink resolving outside job_dir.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/7b8a13cc50d3e845. Report an issue: GitHub.