Script lock reference#
Script lock data records a concrete resolved environment for a script. It is generated from the script’s dependency input and later used to create a cached environment without solving from metadata.
Requirements#
Lock support uses conda’s registered
environment exporter
and
environment specifier
plugins, both keyed by conda’s
EnvironmentFormat. The default format is
rattler-lock-v6, provided by conda-lockfiles.
Install it in the environment that provides conda exec:
conda install -n base -c conda-forge conda-lockfiles
If the format is missing, conda-exec raises ScriptLockError.
Commands#
Generate or refresh a sidecar lockfile:
conda exec --lock script.py
conda exec --lock --refresh script.py
Embed lock data in the script:
conda exec --lock --embed script.py
Ignore discovered lock data for one run:
conda exec --ignore-lock script.py
Generate lock data for multiple conda subdirs:
conda exec --lock \
--platform linux-64 \
--platform osx-arm64 \
--platform win-64 \
script.py
--lock is only supported for existing script files. --embed requires
--lock.
Sidecar filenames#
With the default lock format, conda-exec discovers these sidecar names next
to script.py:
script.py.conda-exec.lock
script.conda-exec.lock
script.py.conda-exec.lock is the default write target. The shorter
script.conda-exec.lock form is also discovered for compatibility with
common sidecar naming conventions.
For non-default lock formats, sidecar names are derived from the lock exporter and specifier plugin metadata.
Embedded block#
Embedded lock data uses a generated metadata block:
# /// conda-exec-lock
# # conda-exec-lock-input-sha256: <digest>
# ...lock data...
# ///
This block is generated state, not dependency intent. Keep human-authored
requirements in the # /// script block.
The digest line has two # characters in the script source: one is the
metadata block comment prefix, and one is part of the generated lock
content.
When embedding lock data, conda-exec preserves the script’s executable mode bits and writes the file atomically.
Discovery order#
When running conda exec script.py, conda-exec checks:
embedded
# /// conda-exec-lockcontent already read from the scriptsidecar lockfiles next to the script
the PEP 723 metadata block
Embedded lock data wins because it is part of the single-file artifact. Sidecar lockfiles are the normal repository workflow.
When locks are ignored#
Discovered lock data is ignored when any of these are present:
--ignore-lock--lock--refresh--with--channel
Those flags either ask conda-exec to generate new lock data or change the dependency input for this run. conda-exec solves from metadata instead.
Input digest#
Generated lock data starts with:
# conda-exec-lock-input-sha256: <digest>
The digest is computed from:
script conda channels
script conda dependencies
script PyPI dependencies
requires-pythonCLI
--withspecsCLI
--channelvalues
conda-exec only auto-uses generated lock data when the stored digest matches the current dependency input. This prevents stale sidecars from silently overriding changed script metadata.
Cache keys#
Environments created from metadata use a script--<hash> key derived from
metadata.
Environments created from lock data also use a script--<hash> key, but
the hash is derived from the lock content. Updating lock data creates a new
cached environment.
Lock size limits#
Sidecar and embedded lock data are limited to 10 MB. Larger lockfiles raise
ScriptLockError, and oversized embedded locks are not written.
Fallback behavior#
If lock data is discovered but cannot be used, conda-exec behaves differently depending on whether metadata is available:
If the script still has a valid
# /// scriptblock, conda-exec warns and falls back to solving from metadata.If the script has no metadata, the lock error is fatal because there is no dependency input to solve from.
Use --ignore-lock when you intentionally want to bypass lock data and
solve from metadata.