rust-lang/cargo · error · anyhow::Error
unexpected variable `{variable}` in resolver.lockfile-path `
Error message
unexpected variable `{variable}` in resolver.lockfile-path `{raw_template}` What it means
Thrown while resolving `resolver.lockfile-path` in `Workspace::validate` (src/workspace/workspace.rs:373). Cargo calls `resolve_templated_path` with an empty replacements table (`let replacements: [(&str, &str); 0] = [];` at line 372), so ANY `{variable}` form in the path is rejected as `UnexpectedVariable`. The error echoes the offending variable name and the raw template.
Source
Thrown at src/workspace/workspace.rs:380
if config.incompatible_publish_age.is_some() {
self.gctx().shell().warn(
"ignoring `resolver.incompatible-publish-age` without `-Zmin-publish-age`",
)?;
}
warn_unused_min_publish_age(self.gctx())?;
}
if let Some(lockfile_path) = config.lockfile_path {
// Reserve the ability to add templates in the future.
let replacements: [(&str, &str); 0] = [];
let path = lockfile_path
.resolve_templated_path(self.gctx(), replacements)
.map_err(|e| match e {
context::ResolveTemplateError::UnexpectedVariable {
variable,
raw_template,
} => {
anyhow!(
"unexpected variable `{variable}` in resolver.lockfile-path `{raw_template}`"
)
}
context::ResolveTemplateError::UnexpectedBracket { bracket_type, raw_template } => {
let (btype, literal) = match bracket_type {
context::BracketType::Opening => ("opening", "{"),
context::BracketType::Closing => ("closing", "}"),
};
anyhow!(
"unexpected {btype} bracket `{literal}` in build.build-dir path `{raw_template}`"
)
}
})?;
if !path.ends_with(LOCKFILE_NAME) {
bail!("the `resolver.lockfile-path` must be a path to a {LOCKFILE_NAME} file");
}
if path.is_dir() {View on GitHub (pinned to 0e07a15537)
Solutions
- Remove all `{...}` template syntax from `resolver.lockfile-path` and use a concrete relative or absolute path.
- If you need workspace-root-relative behavior, compute the path out-of-band (env var, build script) since cargo does not expand variables here.
- Verify the value comes from the right config layer if you did not set it explicitly.
Example fix
# before
[resolver]
lockfile-path = "{workspace_root}/Cargo.lock"
# after
[resolver]
lockfile-path = "Cargo.lock" Defensive patterns
Strategy: validation
Validate before calling
fn has_template_vars(s: &str) -> bool { s.contains('{') || s.contains('}') }
// reject resolver.lockfile-path values with any template syntax
assert!(!has_template_vars(&lockfile_path)); Prevention
- Do not use {variable} syntax in resolver.lockfile-path — no variables are supported.
- Use a concrete path; compute workspace-relative paths outside cargo.
When it happens
Trigger: Setting `resolver.lockfile-path = "{workspace_root}/Cargo.lock"` or any value containing a `{...}` token in `.cargo/config.toml` or the workspace manifest — because no template variables are currently supported for this field.
Common situations: Assuming lockfile-path supports the same templating as other cargo config fields; copy-pasting a templated path from documentation for a different field; leftover `{}` placeholders from migration tooling.
Related errors
- unexpected {btype} bracket `{literal}` in build.build-dir pa
- source ID should have valid URLs
- not implemented
- subcommand is required, add a subcommand to the command alia
- alias {} has unresolvable recursive definition: {} -> {}
AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06).
Data as JSON: /data/errors/87d729603d997968.json.
Report an issue: GitHub.