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

  1. Remove all `{...}` template syntax from `resolver.lockfile-path` and use a concrete relative or absolute path.
  2. If you need workspace-root-relative behavior, compute the path out-of-band (env var, build script) since cargo does not expand variables here.
  3. 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

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


AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06). Data as JSON: /data/errors/87d729603d997968.json. Report an issue: GitHub.