Skip to content

Troubleshoot a hook

Locate the failing layer before changing policy or weakening validation.

Identify the failing operation, program, phase, and logs using the callback contract. Start by finding whether failure occurred in core validation, CPI authentication, policy evaluation, reply validation, or settlement.

Diagnose by symptom

Symptom or errorLikely causeFix and verify
UnsupportedHook during setupUnknown/delta bits, CustomAccounting, or DynamicFee without BeforeSwapSelect supported capabilities and validate the profile
InvalidHookTargetWrong sentinel, nonexecutable program, or core used as its own hookCorrect target binding and program loading
InvalidHookAccountsDescriptor/account mismatch, wrong role/address/owner, duplicates, protected alias, signer extra, or missing transaction writabilityRebuild the exact account list and descriptors from authentication
InvalidHookPermissionRequested phase access or count exceeds pool configuration; invalid external-program declarationsCheck per-phase permissions, including both callbacks
InvalidHookContextInconsistent operation details, sequence, snapshots, direction, or settled resultUse the current typed ABI and matching core build; never fabricate callback context
MissingCoreSignatureHook was called directly or wrong callback authority suppliedSend the operation through core; retain PDA validation
InvalidPoolStateWrong pool version or callback outside entered stateUse the matching core and account contract; do not forge the lifecycle flag
InvalidPolicyKindEconomic example configured for more than BeforeSwap or wrong profileUse its exact phase/profile pair
AlreadyConfiguredRepeated setup against existing policyUse the existing policy; setup is not an update operation
PolicyRejectedClosed time, expired/mismatched proof, or fee boundsRead the structured hook_policy_rejected reason and reproduce the exact boundary
InvalidPayloadNonempty fee/window payload or malformed proof/probe payloadUse the policy's documented encoder
MissingHookResponseNo return data or a different program supplied itSet the final canonical reply from the configured hook
InvalidReplyPhase / InvalidFeeResponseReply mismatches phase, profile, or required fee presenceValidate HookReply against configured capabilities
FeeCapExceededDynamic reply exceeds immutable pool capCorrect the schedule/reply; do not silently clamp unauthorized policy
Custom error 7000..7009Lifecycle probe intentionally rejects phase error - 7000Use empty payload for success; keep phase bytes for rollback tests

Core errors and example-program errors are separate namespaces. Interpret names and logs in the context of the program that failed; the same numeric Anchor offset is not a global error identity. See core errors.

A callback never appears

Confirm its bit is enabled and the operation actually has that callback. Opening/closing a position and collecting fees have none. Before hooks also do not run if account or argument validation fails earlier. A zero liquidity delta rejects rather than becoming a fee-claim callback.

For initialization, do not expect an empty/unassigned pool snapshot. Both initialize callbacks see the serialized candidate pool. A policy that can be configured only after creation is not available during that bootstrap.

A valid proof works for one account but fails for another

Recompute the full domain and authenticated actor. An allowlist leaf is bound to actor, expiry, pool, mint, core protocol, root version, and configured chain namespace. Matching the sibling list alone is insufficient. Use leaf and proof construction to isolate byte encoding from runtime identity.

An after hook fails after token transfers

This still rejects the transaction. Verify committed state and token balances rather than treating an intermediate log as settlement. The payer fee can remain charged. Compare all affected accounts and identify the exact rejecting phase. Preserve authentication and reply checks while correcting the underlying policy or account mismatch.

A working native swap is rejected by Metis

Check that a matching HookQuoteAdapter is bound, all declared policy accounts and a coherent Clock snapshot were refreshed, and required actor/payload context is present. The external evaluator may also be rejecting the policy itself, such as a closed window or expired proof. Continue with Metis compatibility; do not suppress rejection or quote a different policy.