Troubleshooting
Bridge ABI mismatch
Section titled “Bridge ABI mismatch”[ahoi] bridge ABI mismatch: the wasm module speaks ABI v2,but this JS bridge expects v1.Align the `ahoi` crate and npm package versions.The ahoi crate and @acheul/ahoi-js are from different releases.
Upgrade both together. If you pin one version, pin both.
BorrowConflict
Section titled “BorrowConflict”panicked at src/lib.rs:265:39:called `Result::unwrap()` on an `Err` value: BorrowConflictA guard on the same root stock was still alive when another one was taken, and at least one of them was a write.
// wrong: the read guard lives to the end of the statementstate.count().set(*state.count().read() + 1);
// right: the guard is dropped before anything else runslet next = { let mut c = state.count().write(); *c += 1; *c};The same applies across different fields of one stock, which is the version that surprises people. Borrows are tracked per root, not per path:
// wrong: disjoint fields, but one root and overlapping guardslet value = state.value().read();*state.runs().write() += 1;
// rightlet value = *state.value().read();*state.runs().write() += value as u32;A memo that writes a counter while reading other state is the usual way this
shows up. Give the counter its own Stock and the conflict cannot happen.
In a debug build the line number is yours, not one inside ahoi. Release
builds compile that tracking out, so diagnose this with --dev.
Remember a wasm panic aborts the module: reload the page after fixing.
Hails get an initial value but never update
Section titled “Hails get an initial value but never update”set_js_hail_dispatcher() is missing from your root pier.
fn run_pier(key: Pier) { match key { Pier::Top => { set_js_hail_dispatcher(); // this provide_context(Stock::new(State::default())); } }}Without it, Rust has nowhere to push values, so the first read works and nothing after it does.
Nothing changed after editing Rust
Section titled “Nothing changed after editing Rust”Wasm cannot hot-reload. Rebuild, then make sure the page fully reloads:
wasm-pack build --target web --devif (import.meta.hot) import.meta.hot.accept(() => import.meta.hot!.invalidate());Types are stale after changing a key enum
Section titled “Types are stale after changing a key enum”Run cargo test. That is what regenerates bindings/: both your exporter’s
types and ahoi’s ret maps.
Nothing else triggers it, and wasm-pack build will happily build against the
old bindings.
A serde attribute is a compile error
Section titled “A serde attribute is a compile error”Key enums must use serde’s default, externally tagged representation. Renaming variants or changing the representation is rejected at compile time.
Change the variant name in Rust instead of renaming it in serde.
A map value is not an object
Section titled “A map value is not an object”HashMap<K, V> arrives as a JavaScript Map, not a plain object.
const counts = pier.readHail("FruitCounts"); // Map<string, number>
counts.get("apple"); // rightcounts["apple"]; // undefinedusePier / usePierId throws
Section titled “usePier / usePierId throws”There is no PierProvider above the component, or in Svelte no providePier
was called in an ancestor.
In React, remember the provider renders children only after its sphere exists; a component rendered outside the provider will not find one.
Vue: changing the pier prop does nothing
Section titled “Vue: changing the pier prop does nothing”The pier prop is read once during setup. Re-mount the provider to switch:
<PierProvider :key="currentPier" :pier="currentPier"> <Panel /></PierProvider>Svelte: context errors inside a handler
Section titled “Svelte: context errors inside a handler”providePier, useHail, useReadHail, and useTell use setContext,
getContext, and onDestroy, so they only work during component
initialisation.
Capture them at the top of <script>:
<script lang="ts"> const tell = useTell(); // here
function onClick() { tell("Increase"); // not here }</script>A key’s type is unknown
Section titled “A key’s type is unknown”The ret map is not reaching createAhoi. Check that you passed all five type
parameters:
createAhoi<Pier, Hail, Tell, HailRets, TellRets>({ /* ... */ });A missing HailRets falls back to unknown for hails, and a missing
TellRets to undefined for tells.
Writing to a derived value does nothing
Section titled “Writing to a derived value does nothing”The path does not exist: an index past the end, a missing map key, a field of an inactive enum variant.
That is by design: writes to an absent path are ignored rather than panicking.
The returned Option tells you when you need to know.
if state.items().get(10).set(1).is_none() { // there is no item 10}