{"record":{"id":"5d20ca02e200b436","repo":"Pumpkin-MC/Pumpkin","slug":"invalid-palette-index-0","errorCode":null,"errorMessage":"Invalid palette index: {0}","messagePattern":"Invalid palette index: (.+?)","errorType":"error_code","errorClass":"TemplateError","httpStatus":null,"severity":"error","filePath":"crates/pumpkin-world/src/generation/structure/template/structure_template.rs","lineNumber":28,"sourceCode":"use pumpkin_util::math::{block_box::BlockBox, vector3::Vector3};\nuse thiserror::Error;\n\nuse super::processor::StructureProcessor;\nuse crate::generation::structure::structures::jigsaw::JigsawJointType;\n\n/// Errors that can occur when loading or saving a structure template.\n#[derive(Debug, Error)]\npub enum TemplateError {\n    #[error(\"Failed to decompress NBT: {0}\")]\n    NbtError(#[from] pumpkin_nbt::Error),\n\n    #[error(\"Missing required field: {0}\")]\n    MissingField(&'static str),\n\n    #[error(\"Invalid field type for {0}\")]\n    InvalidFieldType(&'static str),\n\n    #[error(\"Invalid palette index: {0}\")]\n    InvalidPaletteIndex(u32),\n}\n\n/// Settings used when placing, transforming, or querying a [`StructureTemplate`].\n#[derive(Clone, Debug)]\npub struct StructurePlaceSettings {\n    pub mirror: Mirror,\n    pub rotation: Rotation,\n    pub rotation_pivot: Vector3<i32>,\n    pub bounding_box: Option<BlockBox>,\n    pub ignore_entities: bool,\n    pub apply_waterlogging: bool,\n    pub known_shape: bool,\n    pub processors: Vec<StructureProcessor>,\n    pub finalize_entities: bool,\n    pub palette_index: Option<usize>,\n}\n","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/Pumpkin-MC/Pumpkin/blob/8d4639e25a57c15e47448ec327c780d41bbf2356/crates/pumpkin-world/src/generation/structure/template/structure_template.rs#L10-L46","documentation":"TemplateError::InvalidPaletteIndex(u32) is a variant of TemplateError indicating that a block in a structure template references a palette index that does not exist in the loaded palette. The payload is the offending index. It exists so template loading can fail loudly instead of silently placing wrong blocks.","triggerScenarios":"During StructureTemplate::load/load_palette, a block entry's 'state' integer points past the end of the palette list (state index >= palette.len()). Note the current load path in this codebase falls back to minecraft:air via palette.state_for, so this variant primarily surfaces when palette index validation is enforced or in downstream placement code.","commonSituations":"Templates whose 'blocks' list was edited without updating palette indices; off-by-one or 1-based vs 0-based index mistakes in custom template generators; truncated palettes after manual NBT editing.","solutions":["Fix the template's 'state' values so each is within 0..palette_len-1; regenerate the template from a structure block if unsure.","If generating templates programmatically, look up each block state's palette index from the palette you built instead of hardcoding indices.","Validate all block 'state' values against the palette size before calling load.","As a defensive caller, treat the air-fallback behavior as a silent corruption signal and validate templates separately."],"exampleFix":"// before: hardcoded index that may not exist\ncompound.put_int(\"state\", 7);\n// after: index resolved from the palette you wrote\nlet idx = palette_index_for_state(&palette, &state);\ncompound.put_int(\"state\", idx as i32);","handlingStrategy":"validation","validationCode":"fn palette_indices_valid(nbt: &NbtCompound) -> bool {\n    let palette_len = nbt.get_list(\"palette\").map(|p| p.len())\n        .or_else(|| nbt.get_list(\"palettes\").and_then(|ps| ps.first()).and_then(|p| if let NbtTag::List(l) = p { Some(l.len()) } else { None }))\n        .unwrap_or(0);\n    nbt.get_list(\"blocks\").map(|blocks| blocks.iter().all(|b| {\n        b.get_compound(\"state\").is_none() &&\n        b.get_int(\"state\").map(|s| (s as usize) < palette_len).unwrap_or(false)\n    })).unwrap_or(true)\n}","typeGuard":"fn valid_state_index(idx: i32, palette_len: usize) -> bool {\n    idx >= 0 && (idx as usize) < palette_len\n}","tryCatchPattern":"match template.load(&compound) {\n    Err(TemplateError::InvalidPaletteIndex(idx)) => eprintln!(\"block references palette index {idx} which does not exist\"),\n    Err(e) => return Err(e),\n    Ok(()) => {}\n}","preventionTips":["Derive block 'state' indices from the palette you built, never hardcode them","Remember palette indices are 0-based","Validate all state indices against palette length before load","Regenerate templates instead of editing palette entries in place"],"tags":["nbt","structure-template","palette","index-out-of-range"],"backgroundTag":"index-out-of-bounds","analyzedSha":"8d4639e25a57c15e47448ec327c780d41bbf2356","analyzedAt":"2026-09-09T15:32:22.916Z","contentChangedAt":"2026-09-09T15:32:22.916Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}