gfx-rs/wgpu · error
Unexpected sign({:?})
Error message
Unexpected sign({:?}) What it means
Panic in the SPIR-V backend's `MathFunction::Sign` lowering. The GLSL.std.450 extended instruction differs per scalar kind (FSign for floats, SSign for signed ints); if `arg_scalar_kind` is None or an unsupported kind (e.g. Uint, Bool), the `unimplemented!()` arm fires. Note unsigned `sign` is not provided by GLSL.std.450.
Source
Thrown at naga/src/back/spv/block.rs:1662
)),
Mf::Cross => MathOp::Ext(spirv::GlslStd450Op::Cross),
Mf::Distance => MathOp::Ext(spirv::GlslStd450Op::Distance),
Mf::Length => MathOp::Ext(spirv::GlslStd450Op::Length),
Mf::Normalize => MathOp::Ext(spirv::GlslStd450Op::Normalize),
Mf::FaceForward => MathOp::Ext(spirv::GlslStd450Op::FaceForward),
Mf::Reflect => MathOp::Ext(spirv::GlslStd450Op::Reflect),
Mf::Refract => MathOp::Ext(spirv::GlslStd450Op::Refract),
// exponent
Mf::Exp => MathOp::Ext(spirv::GlslStd450Op::Exp),
Mf::Exp2 => MathOp::Ext(spirv::GlslStd450Op::Exp2),
Mf::Log => MathOp::Ext(spirv::GlslStd450Op::Log),
Mf::Log2 => MathOp::Ext(spirv::GlslStd450Op::Log2),
Mf::Pow => MathOp::Ext(spirv::GlslStd450Op::Pow),
// computational
Mf::Sign => MathOp::Ext(match arg_scalar_kind {
Some(crate::ScalarKind::Float) => spirv::GlslStd450Op::FSign,
Some(crate::ScalarKind::Sint) => spirv::GlslStd450Op::SSign,
other => unimplemented!("Unexpected sign({:?})", other),
}),
Mf::Fma => MathOp::Ext(spirv::GlslStd450Op::Fma),
Mf::Mix => {
let selector = arg2.unwrap();
let selector_ty =
self.fun_info[selector].ty.inner_with(&self.ir_module.types);
match (arg_ty, selector_ty) {
// if the selector is a scalar, we need to splat it
(
&crate::TypeInner::Vector { size, .. },
&crate::TypeInner::Scalar(scalar),
) => {
let selector_type_id =
self.get_numeric_type_id(NumericType::Vector { size, scalar });
self.temp_list.clear();
self.temp_list.resize(size as usize, arg2_id);
let selector_id = self.gen_id();View on GitHub (pinned to 3e11ff59bf)
Solutions
- Avoid `sign` on unsigned values: for uint, replace with `select(0u, 1u, x != 0u)` or compare directly
- Cast to i32/f32 before calling sign: `sign(i32(x))`
- Update naga to a version that either supports the case or reports a validation error
- File a wgpu issue with a minimal shader if the case should be supported
Example fix
// before let s = sign(u); // after let s = sign(i32(u));
Defensive patterns
Strategy: validation
Validate before calling
fn check_sign_operand(module: &naga::Module) -> bool {
// sign supports only Float (FSign) and Sint (SSign)
module.global_expressions.iter().all(|(_, e)| match e {
naga::Expression::Math { fun: naga::MathFunction::Sign, args, .. } => args.iter().all(|a| {
matches!(ty_of(module, *a).inner,
naga::TypeInner::Scalar(s) | naga::TypeInner::Vector { scalar: s, .. }
if matches!(s.kind, naga::ScalarKind::Float | naga::ScalarKind::Sint))
}),
_ => true,
})
} Type guard
fn sign_supported(s: naga::Scalar) -> bool {
matches!(s.kind, naga::ScalarKind::Float | naga::ScalarKind::Sint)
} Prevention
- Never call sign() on unsigned values; express uint sign via select/comparison
- Cast to i32/f32 before sign
- Validate modules before backend emission
- Isolate shader compilation panics with catch_unwind
When it happens
Trigger: A `sign(x)` call in a shader where x's scalar kind is not Float or Sint, most commonly `sign(uint_value)` or a bool-typed expression, during SPIR-V emission in `cache_expression_value`.
Common situations: Ported code from languages where sign works on unsigned ints (e.g. HLSL or generated code); WGSL authors normally get a frontend error first, so this appears with other frontends or IR constructed programmatically.
Related errors
- Unexpected saturate({:?})
- Unexpected firstLeadingBit({:?})
- Unexpected pointer expression {:?}
- not implemented
- not implemented
AI-assisted analysis of gfx-rs/wgpu@3e11ff59bf (2026-09-03).
Data as JSON: /api/errors/9d17da5174837d7c.
Report an issue: GitHub.