Repository: ProvableHQ/leo (2026-04-14T17:29:31Z)

Issue:
[Bug] Compiler panic in SSA const propagation: `ParseIntError { kind: PosOverflow }` on element write to array of size > 256 with `u8` index
The compiler panics with `Parsing guarantees this works.: ParseIntError { kind: PosOverflow }` in [`ast/src/const_eval/evaluate.rs` `literal_to_value`](https://github.com/ProvableHQ/leo/blob/7e6b2a1ad7/crates/ast/src/const_eval/evaluate.rs) when an array element write `t[i] = v` is performed on an array whose length exceeds 256 and the index `i` is typed `u8`. The SSA const propagation pass synthesizes a literal in the index type whose value cannot be represented in `u8`.

MRE:
```leo
program test.aleo {
    fn foo(t: [u8; 257]) -> [u8; 257] {
        t[0u8] = 1u8;
        return t;
    }
}
```

Reproduce: create a minimal `program.json` (`"program": "test.aleo"`), save the MRE as `src/main.leo`, run `leo build`.

Output:
```
thread 'main' panicked at crates/ast/src/const_eval/evaluate.rs:
Parsing guarantees this works.: ParseIntError { kind: PosOverflow }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```

Expected behavior: type checking emits a diagnostic (e.g., `index type too narrow for array length`), or SSA uses an index-type-agnostic representation, instead of panicking.

Git commit: 7e6b2a1ad7
Build: release
rustc 1.96.0-nightly (562dee482 2026-03-21)



Discussion:

Patch:
diff --git a/crates/passes/src/write_transforming/visitor.rs b/crates/passes/src/write_transforming/visitor.rs
index d3206fb1c5..32e66efbff 100644
--- a/crates/passes/src/write_transforming/visitor.rs
+++ b/crates/passes/src/write_transforming/visitor.rs
@@ -81,7 +81,7 @@ impl<'a> WriteTransformingVisitor<'a> {
             for (i, member) in members.iter().cloned().enumerate() {
                 // Create a definition for each array index.
                 let index = Literal::integer(
-                    IntegerType::U8,
+                    IntegerType::U32,
                     i.to_string(),
                     Default::default(),
                     self.state.node_builder.next_id(),


Test patch:
diff --git a/tests/expectations/compiler/bugs/b29325.out b/tests/expectations/compiler/bugs/b29325.out
new file mode 100644
index 0000000000..82e7c5b7f5
--- /dev/null
+++ b/tests/expectations/compiler/bugs/b29325.out
@@ -0,0 +1,6 @@
+program test.aleo;
+
+function foo:
+    input r0 as [u8; 257u32].private;
+    cast 1u8 r0[1u32] r0[2u32] r0[3u32] r0[4u32] r0[5u32] r0[6u32] r0[7u32] r0[8u32] r0[9u32] r0[10u32] r0[11u32] r0[12u32] r0[13u32] r0[14u32] r0[15u32] r0[16u32] r0[17u32] r0[18u32] r0[19u32] r0[20u32] r0[21u32] r0[22u32] r0[23u32] r0[24u32] r0[25u32] r0[26u32] r0[27u32] r0[28u32] r0[29u32] r0[30u32] r0[31u32] r0[32u32] r0[33u32] r0[34u32] r0[35u32] r0[36u32] r0[37u32] r0[38u32] r0[39u32] r0[40u32] r0[41u32] r0[42u32] r0[43u32] r0[44u32] r0[45u32] r0[46u32] r0[47u32] r0[48u32] r0[49u32] r0[50u32] r0[51u32] r0[52u32] r0[53u32] r0[54u32] r0[55u32] r0[56u32] r0[57u32] r0[58u32] r0[59u32] r0[60u32] r0[61u32] r0[62u32] r0[63u32] r0[64u32] r0[65u32] r0[66u32] r0[67u32] r0[68u32] r0[69u32] r0[70u32] r0[71u32] r0[72u32] r0[73u32] r0[74u32] r0[75u32] r0[76u32] r0[77u32] r0[78u32] r0[79u32] r0[80u32] r0[81u32] r0[82u32] r0[83u32] r0[84u32] r0[85u32] r0[86u32] r0[87u32] r0[88u32] r0[89u32] r0[90u32] r0[91u32] r0[92u32] r0[93u32] r0[94u32] r0[95u32] r0[96u32] r0[97u32] r0[98u32] r0[99u32] r0[100u32] r0[101u32] r0[102u32] r0[103u32] r0[104u32] r0[105u32] r0[106u32] r0[107u32] r0[108u32] r0[109u32] r0[110u32] r0[111u32] r0[112u32] r0[113u32] r0[114u32] r0[115u32] r0[116u32] r0[117u32] r0[118u32] r0[119u32] r0[120u32] r0[121u32] r0[122u32] r0[123u32] r0[124u32] r0[125u32] r0[126u32] r0[127u32] r0[128u32] r0[129u32] r0[130u32] r0[131u32] r0[132u32] r0[133u32] r0[134u32] r0[135u32] r0[136u32] r0[137u32] r0[138u32] r0[139u32] r0[140u32] r0[141u32] r0[142u32] r0[143u32] r0[144u32] r0[145u32] r0[146u32] r0[147u32] r0[148u32] r0[149u32] r0[150u32] r0[151u32] r0[152u32] r0[153u32] r0[154u32] r0[155u32] r0[156u32] r0[157u32] r0[158u32] r0[159u32] r0[160u32] r0[161u32] r0[162u32] r0[163u32] r0[164u32] r0[165u32] r0[166u32] r0[167u32] r0[168u32] r0[169u32] r0[170u32] r0[171u32] r0[172u32] r0[173u32] r0[174u32] r0[175u32] r0[176u32] r0[177u32] r0[178u32] r0[179u32] r0[180u32] r0[181u32] r0[182u32] r0[183u32] r0[184u32] r0[185u32] r0[186u32] r0[187u32] r0[188u32] r0[189u32] r0[190u32] r0[191u32] r0[192u32] r0[193u32] r0[194u32] r0[195u32] r0[196u32] r0[197u32] r0[198u32] r0[199u32] r0[200u32] r0[201u32] r0[202u32] r0[203u32] r0[204u32] r0[205u32] r0[206u32] r0[207u32] r0[208u32] r0[209u32] r0[210u32] r0[211u32] r0[212u32] r0[213u32] r0[214u32] r0[215u32] r0[216u32] r0[217u32] r0[218u32] r0[219u32] r0[220u32] r0[221u32] r0[222u32] r0[223u32] r0[224u32] r0[225u32] r0[226u32] r0[227u32] r0[228u32] r0[229u32] r0[230u32] r0[231u32] r0[232u32] r0[233u32] r0[234u32] r0[235u32] r0[236u32] r0[237u32] r0[238u32] r0[239u32] r0[240u32] r0[241u32] r0[242u32] r0[243u32] r0[244u32] r0[245u32] r0[246u32] r0[247u32] r0[248u32] r0[249u32] r0[250u32] r0[251u32] r0[252u32] r0[253u32] r0[254u32] r0[255u32] r0[256u32] into r1 as [u8; 257u32];
+    output r1 as [u8; 257u32].private;
diff --git a/tests/expectations/passes/write_transforming/member_access_gets_correct_type.out b/tests/expectations/passes/write_transforming/member_access_gets_correct_type.out
index cf6bc92f85..5497fe2975 100644
--- a/tests/expectations/passes/write_transforming/member_access_gets_correct_type.out
+++ b/tests/expectations/passes/write_transforming/member_access_gets_correct_type.out
@@ -11,11 +11,11 @@ program test.aleo {
     fn nested2(s: test.aleo::S, t: test.aleo::T) -> (test.aleo::S, test.aleo::T) {
         let t#x$0 = t.x;
         let t#y$1 = t.y;
-        let t#y$1#0$3 = t#y$1[0u8];
-        let t#y$1#1$4 = t#y$1[1u8];
+        let t#y$1#0$3 = t#y$1[0u32];
+        let t#y$1#1$4 = t#y$1[1u32];
         let t#y$1#1$4#x$6 = t#y$1#1$4.x;
         let t#y$1#1$4#y$7 = t#y$1#1$4.y;
-        let t#y$1#2$5 = t#y$1[2u8];
+        let t#y$1#2$5 = t#y$1[2u32];
         let t#z$2 = t.z;
         t#y$1#1$4 = s;
         t#y$1#1$4#x$6 = t#y$1#1$4.x;
diff --git a/tests/expectations/passes/write_transforming/simple_write.out b/tests/expectations/passes/write_transforming/simple_write.out
index e762005945..b807d237a3 100644
--- a/tests/expectations/passes/write_transforming/simple_write.out
+++ b/tests/expectations/passes/write_transforming/simple_write.out
@@ -1,9 +1,9 @@
 program test.aleo {
     fn main(x: u32, y: u32, z: u32) -> u32 {
         let a: [u32; 3] = [x, y, z];
-        let a#0$0 = a[0u8];
-        let a#1$1 = a[1u8];
-        let a#2$2 = a[2u8];
+        let a#0$0 = a[0u32];
+        let a#1$1 = a[1u32];
+        let a#2$2 = a[2u32];
         a#0$0 = 0u32;
         return a#1$1;
     }
diff --git a/tests/tests/compiler/bugs/b29325.leo b/tests/tests/compiler/bugs/b29325.leo
new file mode 100644
index 0000000000..d989eb1c86
--- /dev/null
+++ b/tests/tests/compiler/bugs/b29325.leo
@@ -0,0 +1,11 @@
+// Regression test for https://github.com/ProvableHQ/leo/issues/29325.
+// The compiler previously panicked with `ParseIntError { kind: PosOverflow }`
+// when writing to an element of an array of size > 256 using a u8 index,
+// because the SSA write-transforming pass created U8 index literals that
+// overflow for indices >= 256.
+program test.aleo {
+    fn foo(t: [u8; 257]) -> [u8; 257] {
+        t[0u8] = 1u8;
+        return t;
+    }
+}