cross-rs/cross · info
should contain one item
Error message
should contain one item
What it means
This `expect` fires inside PreBuild::Single construction in `pre_build` (src/config.rs:151). After `split('\n')` and a `v.len() == 1` check, the code re-collects into a Vec and calls `next().expect("should contain one item")`. The expect documents the invariant that a single-element iterator always yields one item; it can only fail if that invariant is broken, which is logically unreachable with a correctly-checked len==1.
Solutions
- Treat this as an internal invariant, not a config error; if it ever fires, report it as a bug in cross
- If refactoring, avoid the re-collect: use `v.into_iter().next().unwrap()` immediately after the len check, or match on the slice `if let [line] = &v[..]`
- For config problems, check the PRE_BUILD value in Cross.toml instead — single-line vs multi-line is decided by the len==1 branch, not this expect
Example fix
// before
if v.len() == 1 {
PreBuild::Single { line: v.into_iter().next().expect("should contain one item"), env: true }
}
// after
if let [line] = v.as_slice() {
PreBuild::Single { line: line.clone(), env: true }
} Defensive patterns
Strategy: validation
Validate before calling
let lines: Vec<&str> = pre_build_value.split('\n').collect();
if lines.len() != 1 { /* it will take the PreBuild::Lines branch; no panic path */ } Type guard
fn is_single_line(v: &str) -> bool { !v.contains('\n') } Prevention
- Don't try to 'fix' config values for this error — it is an unreachable internal assertion
- When contributing to cross, keep the length check adjacent to the expect so the invariant stays provable
When it happens
Trigger: Only reachable if the `v.len() == 1` guard is bypassed or the Vec is emptied between the check and the `next()` call. In practice this never fires for users; it is a defensive assertion. A PRE_BUILD config value with no newline (single line) takes this branch.
Common situations: Developers essentially never hit this at runtime; it surfaces as a panic in code review or fuzzing if the guard were ever removed. Confusion usually comes from reading the expect message and thinking a config file was malformed.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
AI-assisted analysis of cross-rs/cross@8c1a8aa4b6 (2026-09-13).
Data as JSON: /api/errors/807cf5f3d7839179.
Report an issue: GitHub.
Appendix: source
Thrown at src/config.rs:151
fn image(&self, target: &Target) -> Result<Option<PossibleImage>> {
let get_target = |env: &Environment, var: &str| env.get_target_var(target, var);
get_possible_image(self, "IMAGE", "IMAGE_TOOLCHAIN", get_target, get_target)
}
fn dockerfile(&self, target: &Target) -> ConfVal<String> {
self.get_values_for("DOCKERFILE", target, ToOwned::to_owned)
}
fn dockerfile_context(&self, target: &Target) -> ConfVal<String> {
self.get_values_for("DOCKERFILE_CONTEXT", target, ToOwned::to_owned)
}
fn pre_build(&self, target: &Target) -> ConfVal<PreBuild> {
self.get_values_for("PRE_BUILD", target, |v| {
let v: Vec<_> = v.split('\n').map(String::from).collect();
if v.len() == 1 {
PreBuild::Single {
line: v.into_iter().next().expect("should contain one item"),
env: true,
}
} else {
PreBuild::Lines(v)
}
})
}
fn runner(&self, target: &Target) -> Option<String> {
self.get_target_var(target, "RUNNER")
}
fn passthrough(&self, target: &Target) -> ConfVal<Vec<String>> {
self.get_values_for("ENV_PASSTHROUGH", target, split_to_cloned_by_ws)
}
fn volumes(&self, target: &Target) -> ConfVal<Vec<String>> {
self.get_values_for("ENV_VOLUMES", target, split_to_cloned_by_ws)View on GitHub (pinned to 8c1a8aa4b6)