vercel/turborepo · warning

{message}

Error message

{message}

What it means

When the shim cannot find a locally installed turbo, it runs the globally installed binary and stores a warning in GLOBAL_WARNING_ENV_VAR; the run command (crates/turborepo-lib/src/commands/run.rs:77-85) reads that env var, re-emits the message via the normal logging sinks (respecting --json by routing to the structured sink), then removes the variable. The message itself is 'No locally installed `turbo` found in your repository. Using globally installed version ...'.

Source

Thrown at crates/turborepo-lib/src/commands/run.rs:79

    // Set up structured logging before initializing the global logger so
    // turbo messages during build() are also captured.
    let structured_sink = create_structured_sink(base.opts.log_file_path.as_ref(), base.opts.json);
    if let Some(ref sink) = structured_sink {
        sinks.with_structured_sink(sink.clone());
    }

    // In --json mode, disable the TerminalSink before init_logger so ALL
    // messages (including the shim warning below) go exclusively through
    // the StructuredLogSink.
    if base.opts.json {
        sinks.terminal.disable();
    }

    sinks.init_logger();

    if let Ok(message) = env::var(turborepo_shim::GLOBAL_WARNING_ENV_VAR) {
        turborepo_log::warn(
            turborepo_log::Source::turbo(turborepo_log::Subsystem::Shim),
            message,
        )
        .emit();
        unsafe { env::remove_var(turborepo_shim::GLOBAL_WARNING_ENV_VAR) };
    }

    // When verbosity is active, redirect tracing to a file before build()
    // so SCM, hashing, and config tracing is captured. Only done here
    // (not in the shim) because non-TUI commands should keep stderr output.
    let repo_root = base.repo_root.clone();
    if let Some(path) = subscriber.stderr_redirect_path() {
        // Already redirected (shouldn't happen, but be safe)
        tracing::debug!("stderr already redirected to {path}");
    } else if verbosity > 0 {
        if let Ok(path) = subscriber.redirect_stderr_to_file(repo_root.as_std_path()) {
            tracing::debug!("Verbose tracing redirected to {path}");
        }

View on GitHub (pinned to f9245100cf)

Solutions

  1. Add turbo to the repository's devDependencies with an exact version and run your package manager's install so node_modules/.bin/turbo exists.
  2. Verify resolution after install: `./node_modules/.bin/turbo --version` should match package.json.
  3. In controlled environments where the global is intentional, silence it with TURBO_GLOBAL_WARNING_DISABLED=1 (shim checks 1/true).
  4. For CI, cache node_modules or pre-install dependencies so the shim always finds the local binary.

Example fix

# before: only global turbo installed
npm i -g turbo && turbo run build   # -> No locally installed `turbo` found...

# after: pin turbo in the repo
cat package.json   # "devDependencies": { "turbo": "2.3.3" }
pnpm install
pnpm exec turbo run build
Defensive patterns

Strategy: validation

Validate before calling

#!/usr/bin/env bash
# fail CI when turbo resolves to a global install
if [ ! -x node_modules/.bin/turbo ]; then
  echo "turbo not installed locally — add to devDependencies and install" >&2
  exit 1
fi
exec ./node_modules/.bin/turbo run build

Prevention

When it happens

Trigger: Invoking `turbo run ...` via a global install while node_modules/.bin/turbo is absent (no turbo in devDependencies, or dependencies not installed) and no repo-declared version for the npx fallback. The shim sets the env var before executing the in-process CLI, which relays it here.

Common situations: Fresh clones where install was skipped, Docker images with turbo baked in globally but the project pinned in package.json, and version-drift incidents: CI uses turbo 2.5 global while the repo expects 2.3 local behavior — cache formats and flags diverge.

Related errors


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