QuipNetwork/hashsigs-rs · warning · Error
[{err.code}] {err.message}
Error message
[{err.code}] {err.message} What it means
This is the fallback message format `[CODE] message` produced by js_error in src/wasm/mod.rs when js_sys::Reflect::set fails to attach the `code` property to the JS Error object. The library folds the machine-readable code into the message string so the code is never lost, at the cost of a non-standard message shape.
Solutions
- Parse the code out of the message with /^\[(.+?)\] / when e.code is undefined.
- Prefer matching on the code (from e.code or the parsed prefix) rather than the full message string.
- Verify the JS runtime allows defining properties on Error instances; test Reflect behavior if embedding in a custom host.
- Report/upgrade if your host makes Reflect::set fail, since it degrades the API surface.
Example fix
// before
if (e.message === "invalid public key") { ... }
// after
const m = /^\[(.+?)\] /.exec(e.message);
const code = e.code ?? m?.[1];
if (code === "INVALID_PUBLIC_KEY") { ... } Defensive patterns
Strategy: fallback
Validate before calling
function extractWasmCode(e) {
if (typeof e?.code === 'string') return e.code;
const m = /^\[(.+?)\] /.exec(e?.message ?? '');
return m ? m[1] : null;
} Type guard
function hasFoldedCode(e) {
return e instanceof Error && e.code === undefined && /^\[.+?\] /.test(e.message);
} Try / catch
try {
wasmApi(input);
} catch (e) {
const code = extractWasmCode(e); // works for both property and folded message
if (code === null) throw e;
dispatchByCode(code, e.message.replace(/^\[.+?\] /, ''));
} Prevention
- Never string-match the exact error message; match on the code parsed from e.code or the `[CODE] ` prefix.
- Test your host environment once for Reflect.set support on Error instances to know which message shape to expect.
- Centralize error-code extraction in one helper so both message shapes are handled consistently.
- Avoid freezing/sealing Error objects or using proxy hosts that block property definition when loading wasm modules.
When it happens
Trigger: A WasmErr crosses the wasm->JS boundary while Reflect::set on the Error object returns an error (e.g. exotic JS hosts/proxies where the Error object rejects new property definitions); the returned Error's message becomes "[code] err.message" instead of plain err.message.
Common situations: Running the wasm module in hardened or sandboxed JS environments (frozen objects, unusual realms) where property definition on Error instances fails; code that matches on exact message text breaks because messages now carry a `[CODE] ` prefix; tooling that relies on e.code gets undefined.
Related errors
AI-assisted analysis of QuipNetwork/hashsigs-rs@128c4ccb5c (2026-09-08).
Data as JSON: /api/errors/b130c8b1287a4a57.
Report an issue: GitHub.
Appendix: source
Thrown at src/wasm/mod.rs:1684
}
#[cfg(any(test, feature = "wasm-bindings"))]
fn hex_string(bytes: &[u8]) -> String {
let mut out = String::from("0x");
for byte in bytes {
use core::fmt::Write;
let _ = write!(out, "{byte:02x}");
}
out
}
#[cfg(feature = "wasm-bindings")]
fn js_error(err: WasmErr) -> JsValue {
let e = js_sys::Error::new(&err.message);
if js_sys::Reflect::set(&e, &JsValue::from_str("code"), &JsValue::from_str(err.code)).is_err() {
// Reflect::set failed, so the machine-readable code would be lost off the
// Error object. Fold it into the message so callers never lose it.
return js_sys::Error::new(&format!("[{}] {}", err.code, err.message)).into();
}
e.into()
}
/// Build a serde-boundary error handler tagged with a STATIC argument label
/// (e.g. `"publicKey"`). The label identifies which argument failed to
/// deserialize without ever echoing the caller-supplied value (inputs include
/// secret seeds). Returns a closure so call sites read
/// `.map_err(js_error_from_serde("publicKey"))`.
#[cfg(feature = "wasm-bindings")]
fn js_error_from_serde(label: &'static str) -> impl Fn(serde_wasm_bindgen::Error) -> JsValue {
move |_error| {
js_error(WasmErr {
code: ERR_INVALID_INPUT,
message: format!("invalid {label}: argument shape or field encoding"),
})
}
}View on GitHub (pinned to 128c4ccb5c)