gfx-rs/wgpu · error
Unexpected pointer expression {:?}
Error message
Unexpected pointer expression {:?} What it means
Panic in `write_access_chain` when computing the root of a pointer expression in the SPIR-V backend. The code handles Local/GlobalVariable and FunctionArgument roots; any other expression kind used as a pointer root (e.g. an unexpected intermediate expression after access chains were rewritten) triggers `unimplemented!`. It indicates the backend encountered a pointer form it never expected after earlier lowering passes.
Source
Thrown at naga/src/back/spv/block.rs:2716
block,
)?;
self.temp_list.push(index_id);
}
}
base
}
crate::Expression::GlobalVariable(handle) => {
let gv = &self.writer.global_variables[handle];
break gv.access_id;
}
crate::Expression::LocalVariable(variable) => {
let local_var = &self.function.variables[&variable];
break local_var.id;
}
crate::Expression::FunctionArgument(index) => {
break self.function.parameter_id(index);
}
ref other => unimplemented!("Unexpected pointer expression {:?}", other),
}
};
let (pointer_id, expr_pointer) = if self.temp_list.is_empty() {
(
root_id,
ExpressionPointer::Ready {
pointer_id: root_id,
},
)
} else {
self.temp_list.reverse();
let pointer_id = self.gen_id();
let access =
Instruction::access_chain(result_type_id, pointer_id, root_id, &self.temp_list);
// If we generated some bounds checks, we need to leave it to our
// caller to generate the branch, the access, the load or store, andView on GitHub (pinned to 3e11ff59bf)
Solutions
- Restructure the shader to avoid pointers: pass values by copy or write through the original variable directly
- In function bodies, operate on the global/local variable rather than a pointer temporary
- Update naga/wgpu - pointer handling in the SPIR-V backend has been actively improved
- Reduce the shader and file an issue at github.com/gfx-rs/wgpu
Example fix
// before (WGSL)
fn f(p: ptr<function, f32>) { *p = 1.0; }
let rp = &v;
*rp = 1.0;
// after
v = 1.0; // operate on the variable directly Defensive patterns
Strategy: try-catch
Validate before calling
// scan module expressions for pointer-typed temporaries not rooted in variables/arguments
fn has_unexpected_pointer_roots(module: &naga::Module) -> bool {
module.global_expressions.iter().any(|(_, e)| {
matches!(e, naga::Expression::AccessIndex { base, .. } | naga::Expression::Access { base, .. }
if matches!(module.globals.get(...), /* base resolves to a non-variable pointer root */ _ => false))
})
} Try / catch
let result = std::panic::catch_unwind(|| {
naga::back::spv::write_vec(&module, &naga::back::spv::Options::default(), pipeline_constants, &mut writer_flags)
});
match result {
Ok(spirv) => use_spirv(spirv),
Err(_) => fallback_to_other_backend_or_report(),
} Prevention
- Avoid WGSL pointer temporaries; write through the original variable
- Pass values by copy instead of pointer parameters when targeting SPIR-V
- Use a recent naga/wgpu where SPIR-V pointer handling is more complete
- Pin and test shader compilation in CI to catch backend gaps early
When it happens
Trigger: Loading/storing through a pointer whose root expression is not a variable or function argument - typically a function-parameter pointer, complex pointer-from-value expression, or an IR pattern produced by newer frontend features (e.g. pointer dereference chains in WGSL) that this backend path doesn't model.
Common situations: Shaders using WGSL pointers (`&var`, pointer function parameters) with a naga version whose SPIR-V writer lacks the pattern; more common in `cache_expression_value`/load paths when the module contains pointer-typed temporaries.
Related errors
- Unexpected saturate({:?})
- Unexpected sign({:?})
- Unexpected firstLeadingBit({:?})
- not implemented
- not implemented
AI-assisted analysis of gfx-rs/wgpu@3e11ff59bf (2026-09-03).
Data as JSON: /api/errors/e3f31433ce35447f.
Report an issue: GitHub.