FuelLabs/sway · error

`LoadDataId` refers to a non-existent data section entry

Error message

`LoadDataId` refers to a non-existent data section entry

What it means

During conversion of the allocated abstract instruction set into a final program, the compiler counts non-copy LoadDataId ops (loads whose target is not a small copy-type value) to reserve a pointer slot for each one. Counting requires has_copy_type(data_id), which returns None when the data id does not exist in the data section. The panic fires because a LoadDataId references a DataId that was never inserted into (or was removed from) the data section — an internal invariant violation of the lowering passes.

Source

Thrown at sway-core/src/asm_generation/fuel/programs/allocated.rs:61

        //
        // We reserve one data section pointer slot for each non-copy `LoadDataId`.
        // The slots are filled in-place during the bytecode generation,
        // which does not change the layout.
        //
        // We freeze the worst-case offset of the configurables region, pessimistically
        // assuming that every far jump whose realization can insert a target word
        // into the data section does insert one. `AddrDataId`s pointing to
        // configurables are sized against this worst-case offset. Note that in practice
        // this "pessimization" almost never results in generating two instructions
        // `MOVI` + `ADD` instead of one `ADDI`.
        let num_non_copy_loads = abstract_ops
            .ops
            .iter()
            .filter(|op| match &op.opcode {
                Either::Left(AllocatedInstruction::LoadDataId(_, data_id)) => !self
                    .data_section
                    .has_copy_type(data_id)
                    .expect("`LoadDataId` refers to a non-existent data section entry"),
                _ => false,
            })
            .count();
        self.data_section.reserve_pointer_slots(num_non_copy_loads);

        let (far_jump_sizes, worst_case_far_jump_words) = abstract_ops.collect_far_jumps();
        self.data_section
            .freeze_configurables_base_offset(8 * worst_case_far_jump_words);

        let (realized_ops, mut label_offsets) =
            abstract_ops.lower_to_realized_ops(&mut self.data_section, &far_jump_sizes)?;
        let ops = realized_ops.lower_to_allocated_ops();

        // Collect the entry point offsets.
        let entries = self
            .entries
            .into_iter()
            .map(|(selector, label, name, test_decl_ref)| {

View on GitHub (pinned to dad95cc42b)

Solutions

  1. Verify every LoadDataId emitted during abstract IR lowering is accompanied by inserting the corresponding entry into the data section
  2. Check that data section deduplication/pruning passes do not remove entries still referenced by emitted LoadDataId ops
  3. Reproduce with the failing contract and trace the DataId index/region back to where the load op was created
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at sway-core/src/asm_generation/fuel/programs/allocated.rs:61 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of FuelLabs/sway@dad95cc42b (2026-09-04). Data as JSON: /api/errors/e7a85ef969911950. Report an issue: GitHub.