{"id":"12d1ae467f4a0dbc","repo":"rust-lang/cargo","slug":"must-be-utf-8-in-toml","errorCode":null,"errorMessage":"must be utf-8 in toml","messagePattern":"must be utf-8 in toml","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/context/schema.rs","lineNumber":288,"sourceCode":"            .string(|one| Ok(BuildTargetConfigInner::One(one.to_owned())))\n            .seq(|many| many.deserialize().map(BuildTargetConfigInner::Many))\n            .deserialize(deserializer)\n    }\n}\n\nimpl BuildTargetConfig {\n    /// Gets values of `build.target` as a list of strings.\n    pub fn values(&self, cwd: &Path) -> CargoResult<Vec<String>> {\n        let map = |s: &String| {\n            if s.ends_with(\".json\") {\n                // Path to a target specification file (in JSON).\n                // <https://doc.rust-lang.org/rustc/targets/custom.html>\n                self.inner\n                    .definition\n                    .root(cwd)\n                    .join(s)\n                    .to_str()\n                    .expect(\"must be utf-8 in toml\")\n                    .to_string()\n            } else {\n                // A string. Probably a target triple.\n                s.to_string()\n            }\n        };\n        let values = match &self.inner.val {\n            BuildTargetConfigInner::One(s) => vec![map(s)],\n            BuildTargetConfigInner::Many(v) => v.iter().map(map).collect(),\n        };\n        Ok(values)\n    }\n}\n\n/// The `[resolver]` table.\n///\n/// Example configuration:\n///","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/rust-lang/cargo/blob/0e07a155371a6ce88ae53a2c00df940280c09a67/src/context/schema.rs#L270-L306","documentation":"This panic is in BuildTargetConfig::values(), which resolves build.target config entries. When a target string ends with .json (a custom target spec file path), cargo joins the config definition root with the path and calls .to_str().expect(\"must be utf-8 in toml\"). The invariant is that since the value originated from a TOML string (always UTF-8) and the cwd/root is also expected to be UTF-8, the joined path should be UTF-8.","triggerScenarios":"Setting build.target to a .json path in config while the working directory or config file location contains non-UTF-8 bytes (e.g., on Linux with a non-UTF-8 locale or a directory name with invalid byte sequences). The path join introduces the non-UTF-8 component.","commonSituations":"Running cargo on a system with a non-UTF-8 locale (LC_ALL, LANG set to legacy encodings); a project directory path containing non-UTF-8 characters; referencing a target spec JSON file via a relative path that traverses a non-UTF-8 directory.","solutions":["Use an absolute path for the .json target spec file to avoid joining with a non-UTF-8 cwd.","Ensure the working directory and all ancestor paths are valid UTF-8.","Set locale environment variables (LANG, LC_ALL) to a UTF-8 encoding like en_US.UTF-8."],"exampleFix":"// before\n.join(s).to_str().expect(\"must be utf-8 in toml\").to_string()\n// after\n.join(s).to_str().map(|s| s.to_string())\n    .ok_or_else(|| anyhow::format_err!(\"build.target path `{}` is not valid UTF-8\", s))?","handlingStrategy":"validation","validationCode":"// Ensure cwd is UTF-8 before building with build.target = \"*.json\"\nlet cwd = std::env::current_dir()?;\nif cwd.to_str().is_none() {\n    return Err(\"working directory is not valid UTF-8; build.target .json paths may fail\".into());\n}","typeGuard":"fn is_utf8_path(path: &std::path::Path) -> bool {\n    path.to_str().is_some()\n}","tryCatchPattern":null,"preventionTips":["Keep project directories and all ancestor paths as valid UTF-8.","Set LANG and LC_ALL to a UTF-8 locale (e.g., en_US.UTF-8).","Use absolute UTF-8 paths for build.target .json files in config."],"tags":["rust","cargo","panic","invariant","utf-8","build-target","config","locale"],"analyzedSha":"0e07a155371a6ce88ae53a2c00df940280c09a67","analyzedAt":"2026-08-06T01:46:58.334Z","schemaVersion":2}