Companion
Properties
The dust UTXO selected to pay the fee has a nullifier already in the node's spent set — its coin was consumed on-chain (often by an immediately-prior send) while the local dust checkpoint still listed it as available. The dust-side sibling of 170: 170 is a stale dust root, 196 is an already-spent dust nullifier. Recovery: full-resync dust to the tip so the spent nullifier drops out, reselect an unspent dust UTXO, and retry.
A contract effects check failed.
An unshielded UTXO input doesn't exist on-chain (already spent or never existed).
The dust spend proof is invalid because the dust commitment root it commits to isn't one the node accepts — a stale/lagging local root, or a ctime that resolved to a different root via the node's dust.root_history.get(ctime) predecessor lookup. Recovery: re-sync dust to the chain tip and retry. See #287.
The ZK proof failed verification (wrong/stale public inputs or key mismatch).
The dust spend's ctime fell outside the node's [tblock - grace, tblock] validity window (MalformedTransaction::OutOfDustValidityWindow). The node checks ctime > tblock || ctime + dust_grace_period < tblock. The usual cause is an idle dust state on a long-running chain: its sync_time (the block time of the last replayed dust event) freezes hours behind the advancing tip, so a sync_time- anchored ctime drifts past dust_grace_period (default 3h). The dust-window sibling of 170: 170 = ctime resolved a stale/foreign root, 171 = ctime is out of the time window entirely. Recovery: re-sync dust to the tip so sync_time advances into the window, then retry.