From bb2667ca9bf98415eaa598f03c96f953ae5a74cd Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Tue, 7 Apr 2026 07:33:29 -0500 Subject: [PATCH] Error on `--locked` and `--frozen` when script lockfile is missing (#18832) However, we do not error when these are set as environment variables for backwards compatibility and general safety since those variables could only be intended for project use. Closes https://github.com/astral-sh/uv/issues/18826 --------- Co-authored-by: Claude --- crates/uv/src/commands/project/run.rs | 45 ++++++++++++++++++++------- crates/uv/tests/it/run.rs | 31 +++++++++++------- 2 files changed, 53 insertions(+), 23 deletions(-) diff --git a/crates/uv/src/commands/project/run.rs b/crates/uv/src/commands/project/run.rs index 84e9ae41e..e542d5a2c 100644 --- a/crates/uv/src/commands/project/run.rs +++ b/crates/uv/src/commands/project/run.rs @@ -74,7 +74,8 @@ use crate::commands::reporters::PythonDownloadReporter; use crate::commands::{ExitStatus, diagnostics, project}; use crate::printer::Printer; use crate::settings::{ - FrozenSource, GlobalSettings, LockCheck, ResolverInstallerSettings, ResolverSettings, + FrozenSource, GlobalSettings, LockCheck, LockCheckSource, ResolverInstallerSettings, + ResolverSettings, }; /// Run a command. @@ -359,18 +360,40 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl Some(environment.into_interpreter()) } else { - // If no lockfile is found, warn against `--locked` and `--frozen`. + // If no lockfile is found, error for `--locked` and `--frozen` when provided + // via CLI. For environment variables and configuration, warn instead to avoid + // breaking users who set `UV_LOCKED=1` globally. if let LockCheck::Enabled(lock_check) = lock_check { - warn_user!( - "No lockfile found for Python script (ignoring `{lock_check}`); run `{}` to generate a lockfile", - "uv lock --script".green(), - ); + match lock_check { + LockCheckSource::LockedCli | LockCheckSource::Check => { + bail!( + "Unable to find lockfile for Python script, but `{lock_check}` was provided. To create a lockfile, run `{}`.", + "uv lock --script".green(), + ); + } + LockCheckSource::LockedEnv | LockCheckSource::LockedConfiguration => { + warn_user!( + "No lockfile found for Python script (ignoring `{lock_check}`); run `{}` to generate a lockfile", + "uv lock --script".green(), + ); + } + } } - if frozen.is_some() { - warn_user!( - "No lockfile found for Python script (ignoring `--frozen`); run `{}` to generate a lockfile", - "uv lock --script".green(), - ); + if let Some(frozen_source) = frozen { + match frozen_source { + FrozenSource::Cli => { + bail!( + "Unable to find lockfile for Python script, but `--frozen` was provided. To create a lockfile, run `{}`.", + "uv lock --script".green(), + ); + } + FrozenSource::Env | FrozenSource::Configuration => { + warn_user!( + "No lockfile found for Python script (ignoring `--frozen`); run `{}` to generate a lockfile", + "uv lock --script".green(), + ); + } + } } // Install the script requirements, if necessary. Otherwise, use an isolated environment. diff --git a/crates/uv/tests/it/run.rs b/crates/uv/tests/it/run.rs index e60020488..2d6c47451 100644 --- a/crates/uv/tests/it/run.rs +++ b/crates/uv/tests/it/run.rs @@ -414,15 +414,25 @@ fn run_pep723_script() -> Result<()> { ----- stderr ----- "); - // Running a script with `--locked` should warn. + // Running a script with `--locked` should error. uv_snapshot!(context.filters(), context.run().arg("--locked").arg("main.py"), @" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: Unable to find lockfile for Python script, but `--locked` was provided. To create a lockfile, run `uv lock --script`. + "); + + // Running a script with `UV_LOCKED` should warn (not error). + uv_snapshot!(context.filters(), context.run().env("UV_LOCKED", "1").arg("main.py"), @" success: true exit_code: 0 ----- stdout ----- Hello, world! ----- stderr ----- - warning: No lockfile found for Python script (ignoring `--locked`); run `uv lock --script` to generate a lockfile + warning: No lockfile found for Python script (ignoring `UV_LOCKED=1`); run `uv lock --script` to generate a lockfile "); // If the script can't be resolved, we should reference the script. @@ -974,19 +984,14 @@ fn run_pep723_script_lock() -> Result<()> { "# })?; - // Without a lockfile, running with `--locked` should warn. + // Without a lockfile, running with `--locked` should error. uv_snapshot!(context.filters(), context.run().arg("--locked").arg("main.py"), @" - success: true - exit_code: 0 + success: false + exit_code: 2 ----- stdout ----- - Hello, world! ----- stderr ----- - warning: No lockfile found for Python script (ignoring `--locked`); run `uv lock --script` to generate a lockfile - Resolved 1 package in [TIME] - Prepared 1 package in [TIME] - Installed 1 package in [TIME] - + iniconfig==2.0.0 + error: Unable to find lockfile for Python script, but `--locked` was provided. To create a lockfile, run `uv lock --script`. "); // Explicitly lock the script. @@ -1037,7 +1042,9 @@ fn run_pep723_script_lock() -> Result<()> { ----- stderr ----- Resolved 1 package in [TIME] - Checked 1 package in [TIME] + Prepared 1 package in [TIME] + Installed 1 package in [TIME] + + iniconfig==2.0.0 "); // With a lockfile, running with `--locked` should not warn.