vercel/turborepo · error

lockfile should be in repo

Error message

lockfile should be in repo

What it means

ChangeMapper::lockfile_changed (change_mapper/mod.rs:335) anchors the detected lockfile path against the repo root with turbo_root.anchor(lockfile_path) and `.expect("lockfile should be in repo")` panics when the lockfile is not underneath the root turbo inferred. The invariant assumes package-manager discovery only ever finds the lockfile inside the workspace; when a layout breaks that (nested checkouts, root inference picking the wrong directory), this panic aborts the run.

Source

Thrown at crates/turborepo-repository/src/change_mapper/mod.rs:335

    }

    fn get_changed_packages_from_lockfile(
        &self,
        lockfile_content: &[u8],
    ) -> Result<Vec<ExternalDependencyChange>, ChangeMapError> {
        self.pkg_graph
            .changed_packages_from_lockfile_contents(lockfile_content)
            .map_err(Into::into)
    }

    pub fn lockfile_changed(
        turbo_root: &AbsoluteSystemPath,
        changed_files: &HashSet<AnchoredSystemPathBuf>,
        lockfile_path: &AbsoluteSystemPath,
    ) -> bool {
        let lockfile_path_relative = turbo_root
            .anchor(lockfile_path)
            .expect("lockfile should be in repo");

        changed_files.iter().any(|f| f == &lockfile_path_relative)
    }
}

#[derive(thiserror::Error, Debug)]
pub enum ChangeMapError {
    #[error(transparent)]
    Wax(#[from] wax::BuildError),
    #[error(transparent)]
    ChangedPackages(#[from] ChangedPackagesError),
}

#[cfg(test)]
mod test {
    use std::collections::HashSet;

    use test_case::test_case;

View on GitHub (pinned to f9245100cf)

Solutions

  1. Run turbo from the actual repository root so the lockfile lands inside the inferred root
  2. Verify the inferred root (inspect `turbo run <task> --dry-run=json` root/workspace data) and fix the layout or config that misdirects it
  3. Ensure the lockfile and workspace config (pnpm-workspace.yaml etc.) are inside the checked-out tree, not above it
  4. If the layout is legitimate, report it — the expect should become a real error message

Example fix

# before: run from nested checkout, lockfile one level up
cd repo/apps/web && turbo run build   # panics: lockfile should be in repo
# after: run from the root that contains the lockfile
cd repo && turbo run build --filter=web
Defensive patterns

Strategy: validation

Validate before calling

// before change detection, assert the invariant the panic encodes
let rel = turbo_root.anchor(lockfile_path);
if rel.is_err() {
    anyhow::bail!("lockfile {lockfile_path} is outside turbo root {turbo_root}; run from the repo root");
}

Prevention

When it happens

Trigger: `turbo run` during change detection (watch mode / affected) where the lockfile detected via packageManager inference sits above the directory turbo treats as root — e.g. a partial/nested checkout of a monorepo, or root inference landing on a subdir while pnpm-workspace.yaml/lockfile live at the parent.

Common situations: Sparse or nested checkouts of a monorepo Running turbo from a subdirectory in layouts where the lockfile is one level above the inferred root Unusual TURBO_ROOT / discovery configuration after repo restructuring

Related errors


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