{"record":{"id":"93560c495c3c3f5e","repo":"louis-e/arnis","slug":"scrap-metal-list-is-non-empty","errorCode":null,"errorMessage":"scrap metal list is non-empty","messagePattern":"scrap metal list is non-empty","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"info","filePath":"src/element_processing/amenities.rs","lineNumber":791,"sourceCode":"            \"minecraft:paper\",\n            slot,\n            rng.random_range(1..=10),\n        )),\n        RecyclingLootKind::GlassBlock => Some(build_glass_item(false, slot, rng)),\n        RecyclingLootKind::GlassPane => Some(build_glass_item(true, slot, rng)),\n        RecyclingLootKind::LeatherArmor => {\n            Some(build_leather_item(random_leather_piece(rng), slot, rng))\n        }\n        RecyclingLootKind::EmptyBucket => Some(make_basic_item(\"minecraft:bucket\", slot, 1)),\n        RecyclingLootKind::LeatherBoots => Some(build_leather_item(LeatherPiece::Boots, slot, rng)),\n        RecyclingLootKind::ScrapMetal => Some(build_scrap_metal_item(slot, rng)),\n        RecyclingLootKind::GreenWaste => Some(build_green_waste_item(slot, rng)),\n    }\n}\n\nfn build_scrap_metal_item(slot: i8, rng: &mut impl Rng) -> HashMap<String, Value> {\n    let metals = [\"copper_ingot\", \"iron_ingot\", \"gold_ingot\"];\n    let metal = metals.choose(rng).expect(\"scrap metal list is non-empty\");\n    let count = rng.random_range(1..=3);\n    make_basic_item(&format!(\"minecraft:{metal}\"), slot, count)\n}\n\nfn build_green_waste_item(slot: i8, rng: &mut impl Rng) -> HashMap<String, Value> {\n    #[allow(clippy::match_same_arms)]\n    let (id, count) = match rng.random_range(0..8) {\n        0 => (\"minecraft:tall_grass\", rng.random_range(1..=4)),\n        1 => (\"minecraft:sweet_berries\", rng.random_range(2..=6)),\n        2 => (\"minecraft:oak_sapling\", rng.random_range(1..=2)),\n        3 => (\"minecraft:birch_sapling\", rng.random_range(1..=2)),\n        4 => (\"minecraft:spruce_sapling\", rng.random_range(1..=2)),\n        5 => (\"minecraft:jungle_sapling\", rng.random_range(1..=2)),\n        6 => (\"minecraft:acacia_sapling\", rng.random_range(1..=2)),\n        _ => (\"minecraft:dark_oak_sapling\", rng.random_range(1..=2)),\n    };\n\n    // 25% chance to replace with seeds instead","sourceCodeStart":773,"sourceCodeEnd":809,"githubUrl":"https://github.com/louis-e/arnis/blob/34048924d9365795fb0d832e76140a3fbdc413d9/src/element_processing/amenities.rs#L773-L809","documentation":"`build_scrap_metal_item` picks a metal from a hard-coded 3-element array with `metals.choose(rng).expect(\"scrap metal list is non-empty\")`. `slice::choose` returns None only for an empty slice, so this is an internal invariant assertion — it can never fire while the literal array stays non-empty.","triggerScenarios":"Only if the `metals` array is edited to be empty (e.g. an over-eager refactor removes all entries) or the function is changed to build the list dynamically and it ends up empty.","commonSituations":"Code modification/regression, not runtime user input — users of the released library should never see this panic.","solutions":["Keep the `metals` literal non-empty; it is an invariant of the function","If the list becomes dynamic, check `!metals.is_empty()` before `choose` and return a default item otherwise","Replace `expect` with a compile-time or debug_assert guard during refactors"],"exampleFix":"// before\nlet metal = metals.choose(rng).expect(\"scrap metal list is non-empty\");\n// after\nassert!(!metals.is_empty());\nlet metal = metals.choose(rng).expect(\"scrap metal list is non-empty\");","handlingStrategy":"validation","validationCode":"assert!(!metals.is_empty(), \"scrap metals palette must not be empty\");","typeGuard":"fn non_empty<T>(s: &[T]) -> bool { !s.is_empty() }","tryCatchPattern":null,"preventionTips":["Unit-test that all loot palettes are non-empty","Never refactor constant arrays to empty during feature gating"],"tags":["panic","invariant","loot-generation"],"backgroundTag":"empty-collection-unwrap","analyzedSha":"34048924d9365795fb0d832e76140a3fbdc413d9","analyzedAt":"2026-09-03T14:05:17.283Z","contentChangedAt":"2026-09-03T14:05:17.283Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}