rust-lang/cargo · error

unexpected bracket ` ` in build.build-dir path

Error message

unexpected {btype} bracket `{literal}` in build.build-dir path `{raw_template}`

What it means

During the same `resolver.lockfile-path` templated-path resolution, if the template contains a stray opening (`{`) or closing (`}`) bracket that does not form a valid variable token, `ResolveTemplateError::UnexpectedBracket` is raised. The code maps `BracketType::Opening` to the string `"opening"` + literal `{`, and `BracketType::Closing` to `"closing"` + literal `}`, then interpolates them into the message. Note the message text references `build.build-dir` even though this branch fires during lockfile-path resolution — a likely copy-paste artifact in the source.

Solutions

  1. Remove stray `{` or `}` characters from the `resolver.lockfile-path` value so the template is a plain path.
  2. Verify the path ends with `Cargo.lock` and contains no brace tokens (none are supported).
  3. If you need a literal brace in a path (unusual), avoid this config key since the templater will always interpret braces.

Example fix

# before
[resolver]
lockfile-path = "./build/{Cargo.lock"

# after
[resolver]
lockfile-path = "./build/Cargo.lock"
Defensive patterns

Strategy: validation

Validate before calling

fn balanced_braces(s: &str) -> bool {
    // reject any stray { or } in a path meant as a literal
    !s.contains('{') && !s.contains('}')
}
let lp: String = /* resolver.lockfile-path */;
assert!(balanced_braces(&lp));

Prevention

When it happens

Trigger: Setting `resolver.lockfile-path` to a value with an unbalanced brace such as `./Cargo.lock{` or `./lock}` — a brace that the template parser treats as a bracket token rather than a literal — during `resolve_templated_path` with the empty replacements map.

Common situations: Windows path or shell-variable artifacts leaking into the config (`${HOME}`), JSON/TOML escaping mistakes producing stray braces, or hand-editing the config and leaving a dangling bracket.

Related errors


AI-assisted analysis of rust-lang/cargo@98a09e7e7d (2026-08-11). Data as JSON: /api/errors/dcf04f996d6ef87f. Report an issue: GitHub.

Appendix: source

Thrown at src/workspace/workspace.rs:376

            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() {
                bail!(
                    "`resolver.lockfile-path` `{}` is a directory but expected a file",
                    path.display()
                );
            }
            self.requested_lockfile_path = Some(path);
        }

        Ok(())
    }

View on GitHub (pinned to 98a09e7e7d)