Error Catalog
Tagged-error unions per plugin, with the discriminator slots and when each tag surfaces.
Every plugin raises tagged errors with a _tag discriminator. Effect.catchTag and
Effect.catchTags match on the literal tag string. Most plugins also carry a phase field that
identifies which stage of the lifecycle raised, so consumers can pin behavior by tag + phase rather
than by message substring.
This catalog enumerates the tags exported from each plugin. The fields shown are the load-bearing
discriminator slots; full shapes (and the helper constructors) live in each plugin's errors.ts.
Account
AccountAcquireError—phase: 'validate-name' | 'validate-funding' | 'load-keystore' | 'read-env' | 'decode-inline' | 'bind-signer' | …. Surfaces during account boot.AccountSignError—phase: 'build-tx' | 'sign' | 'submit' | 'no-digest' | 'await-finality' | 'dependent-package-not-found'. Surfaces when an account-bound sign attempt fails.
Action
ActionError—phase: 'discriminator' | 'build' | 'sign' | 'execute-failed' | 'verify'. Single tag covers allaction(...)failure paths.
Coin
CoinError—phase: 'not-found' | 'ambiguous' | 'nested-generic' | 'cap-missing' | 'metadata-fetch' | 'mint-tx'. Surfaces when acoin.fromPackageorcoin.knownreference cannot be resolved or minted.
DeepBook
DeepbookPluginError—phase: 'image-pull' | 'network' | 'publish' | 'create-pools' | 'pyth-publish' | 'pyth-feed'. Local-mode boot and pool seeding.DeepbookConfigError— invaliddeepbook(...)options.ForkIncompatibleError— fork mode rejected an incompatible reference.
Faucet
FaucetUnreachable— transport-level (ECONNREFUSED, DNS, TLS, AbortSignal timeout).FaucetExhausted— wall-clock budget exhausted before a funding attempt landed. Carriesattempts: numberand the underlyinglastCause. The attempt-cap exhausting first re-raises the lastFaucetUnreachable | FaucetBodyErrorverbatim — only a wall-clock timeout surfaces asFaucetExhausted.FaucetBodyError—reason: 'failure-status' | 'invalid-json'. The load-bearing wire invariant: 200 OK with{ status: { Failure } }MUST surface here, not as silent success.FaucetConfigError— invalid strategy config.
The "no strategy registered for this chain" case is not a faucet-plugin tag — it surfaces as the
substrate StrategyNotFoundError (see Substrate).
Host service
HostServiceConfigError— invalidhostService(...)options.HostServiceAcquireError—phase: 'allocate-port' | 'spawn' | 'ready' | 'exit'. Surfaces during dev-server boot and ready-probing.
Package
PublishError—phase: 'hash' | 'scrub' | 'build' | 'publish-tx' | 'parse' | 'verify'. Single tag covers the fulllocalPackage(...)publish path.
Seal
SealError—phase: 'port-alloc' | 'image' | 'keygen' | 'publish' | 'register' | 'config-render'. Local-keygen boot.SealConfigError— invalidseal(...)options.ForkIncompatibleError— fork-mode reference mismatch.
Sui
SuiPluginError—phase: 'image-build' | 'port-allocate' | 'container-start' | 'rpc-probe' | 'faucet-probe' | 'graphql-probe'. Localnet boot.SuiConfigError— invalidsui(...)options.SuiCliError—op-tagged failure from a Sui CLI shell-out.ForkUnsupportedError— fork mode rejected an unsupported request.
Wallet
WalletBootError—phase: 'listen' | 'allocate-port' | 'read-token' | 'write-token' | 'bind-account' | 'route-url' | …. Dev-wallet boot.WalletRequestError—phase: 'origin-missing' | 'origin-forbidden' | 'unauthorized' | 'route-not-found' | 'address-not-found' | 'body-invalid' | …. Per-request rejections inside the running wallet.
Walrus
WalrusPluginError—phase: 'image-build' | 'cluster-network' | 'deploy' | 'exchange' | 'storage-node' | 'proxy'. Local-mode boot.WalrusConfigError— invalidwalrus(...)options.ForkIncompatibleError— fork-mode reference mismatch.
Substrate
Errors raised by the shared substrate runtime rather than a single plugin. The one app-facing tag:
StrategyNotFoundError— no funding strategy is registered for the requested capability key. CarriescapabilityKeyandregisteredKeysso the renderer can show "I asked for X, only Y is wired". This is what a missing SUI faucet strategy surfaces as — there is noFaucet-prefixed strategy-missing tag.
Catching errors in app code
import { Effect } from 'effect';
const program = someEffect.pipe(
Effect.catchTags({
AccountAcquireError: (err) => Effect.logError(`account boot failed at phase ${err.phase}`),
FaucetExhausted: (err) => Effect.logError(`faucet gave up after ${err.attempts} attempts`),
}),
);Plugin-author code that catches its own union should use Effect.catchTag for single-tag handling
and catchTags for the multi-tag form; both narrow on the literal _tag discriminator.