vercel/turborepo · critical

collapsed path should be absolute: {err:?}

Error message

collapsed path should be absolute: {err:?}

What it means

collapse() resolves `.`/`..` components by walking a component stack and rebuilding a Utf8PathBuf; the first component was just debug_asserted to be a root/prefix component, so the following AbsoluteSystemPathBuf::new can only fail if that invariant is already broken. Pure internal invariant panic in turborepo-paths.

Source

Thrown at crates/turborepo-paths/src/absolute_system_path.rs:404

                }
                Utf8Component::ParentDir => {
                    // should error if there's nothing popped
                    stack.pop();
                }
                c => stack.push(c),
            }
        }
        debug_assert!(
            matches!(
                stack.first(),
                Some(Utf8Component::RootDir) | Some(Utf8Component::Prefix(_))
            ),
            "expected absolute path to start with root/prefix"
        );

        match AbsoluteSystemPathBuf::new(stack.into_iter().collect::<Utf8PathBuf>()) {
            Ok(path) => path,
            Err(err) => panic!("collapsed path should be absolute: {err:?}"),
        }
    }

    // TODO: consider consolidating with `relation_to_path` below
    pub fn contains(&self, other: &Self) -> bool {
        // On windows, trying to get a relative path between files on different volumes
        // is an error. We don't care about the error, it's good enough for us to say
        // that one path doesn't contain the other if they're on different volumes.
        #[cfg(windows)]
        if self.components().next() != other.components().next() {
            return false;
        }
        let this = self.collapse();
        let other = other.collapse();
        let rel = AnchoredSystemPathBuf::relative_path_between(&this, &other);
        rel.components().next() != Some(Utf8Component::ParentDir)
    }

View on GitHub (pinned to f9245100cf)

Solutions

  1. Upgrade turborepo
  2. Report a minimal reproduction (the exact path string) if it recurs
Defensive patterns

Strategy: fallback

Try / catch

let cleaned = std::panic::catch_unwind(|| collapse(&path));
if let Ok(p) = cleaned { use(p) } else { use(path.clone()) /* skip collapsing */ }

Prevention

When it happens

Trigger: Internal misuse or regression in the component-collapsing algorithm only; there is no user input that legitimately reaches it.

Common situations: Would manifest as a turbo crash during path normalization after an internal bug; not config-triggerable.

Related errors


AI-assisted analysis of vercel/turborepo@f9245100cf (2026-08-17). Data as JSON: /api/errors/eeec336d6ec93788. Report an issue: GitHub.