Summary
When a delegated account's post-delegation actions fail, the validator schedules the automatic undelegation, but dlp rejects the base transaction with InstructionError(2, Custom(0)) (DlpError::InvalidAuthority). The account stays owned by dlp on base. The intent is stored as failed and is never retried.
Environment
- magicblock-validator
dev @ 9cc3fd1a, dlp pin dcd46dc
- base: local test validator, dlp cloned from mainnet (2026-04-29 build)
- reproduced twice with redsuite
redshift/post_delegation_token_transfer
Steps to reproduce
- On base:
assign a fresh system wallet to dlp, then delegate_with_actions(payer, wallet, None, DelegateArgs { validator: <ER identity>, .. }, [action]), where action is any instruction that fails at execution (we use an SPL transfer larger than the source balance).
- Read the wallet on the ER. The ER clones it and runs the action.
- Wait for the wallet's owner on base to return to the system program.
Observed
ER log:
WARN magicblock_chainlink::chainlink::fetch_cloner: Post-delegation actions could not be satisfied; undelegating pubkey=BK91x… error=ClonerError(FailedToCloneRegularAccount(…, Engine("transaction execution failed: Error processing Instruction 6: custom program error: 0x1")))
ERROR execute{intent_id=8}: … Failed to execute intent bundle intent_id=8 error=FailedToFinalizeError { err: InternalError(MagicBlockRpcClientError(SentTransactionError(InstructionError(2, Custom(0)), 263axv…))), commit_signature: None, finalize_signature: Some(263axv…) }
WARN execute{intent_id=8}: … Intent execution resulted in stuck accounts stuck_accounts=Some([BK91x…])
Committor DB, table commit_status, row for the intent:
commit_type=EmptyAccount commit_strategy=StateArgs undelegate=1 data=None lamports=2000000000
delegated_account_owner=MagicRootDRJ5atQjSJUxFjXzjeZXMADHUDznbk22gy
commit_status=FailedProcess retries_count=0
The delegation record on base says owner = 11111111111111111111111111111111. The base transaction is [cu_limit, cu_price, commit_state, finalize, undelegate]; index 2 is commit_state.
Expected
The wallet's owner on base returns to the system program, as it did on master.
Root cause
magicblock-chainlink/src/cloner/mod.rs:127, undelegation_action, builds a generic MagicBlockInstruction::ScheduleIntentBundle. The engine runs it as a MagicRootInstruction::PostFinalize action, so the Magic program sees a CPI from MagicRoot.
programs/magicblock/src/magic_scheduled_base_intent.rs:601 calls CommittedAccount::from_account_shared(pubkey, &account, context.parent_program_id) with parent_program_id = Some(MagicRoot).
magicblock-core/src/intent/types.rs:57: account.owner = parent_program_id.unwrap_or(account.owner); sets the owner to MagicRoot.
magicblock-committor-service/src/tasks/commit_task.rs:57 passes committed_account.account.owner to dlp_api::instruction_builder::commit_state, which derives the program-config PDA from it.
- dlp derives the program-config PDA from
delegation_record.owner (src/processor/fast/commit_state.rs:238). dlp-api/src/requires.rs:604 returns DlpError::InvalidAuthority (0) on mismatch.
Impact
Any delegation whose actions fail leaves the account under dlp on base, and the user cannot recover it without the validator key. The committor's error mapper has no case for Custom(0) on a commit task, so there is no retry, and the startup replay reuses the stored MagicRoot owner and fails the same way.
Summary
When a delegated account's post-delegation actions fail, the validator schedules the automatic undelegation, but dlp rejects the base transaction with
InstructionError(2, Custom(0))(DlpError::InvalidAuthority). The account stays owned by dlp on base. The intent is stored as failed and is never retried.Environment
dev@9cc3fd1a, dlp pindcd46dcredshift/post_delegation_token_transferSteps to reproduce
assigna fresh system wallet to dlp, thendelegate_with_actions(payer, wallet, None, DelegateArgs { validator: <ER identity>, .. }, [action]), whereactionis any instruction that fails at execution (we use an SPL transfer larger than the source balance).Observed
ER log:
WARN magicblock_chainlink::chainlink::fetch_cloner: Post-delegation actions could not be satisfied; undelegating pubkey=BK91x… error=ClonerError(FailedToCloneRegularAccount(…, Engine("transaction execution failed: Error processing Instruction 6: custom program error: 0x1")))
ERROR execute{intent_id=8}: … Failed to execute intent bundle intent_id=8 error=FailedToFinalizeError { err: InternalError(MagicBlockRpcClientError(SentTransactionError(InstructionError(2, Custom(0)), 263axv…))), commit_signature: None, finalize_signature: Some(263axv…) }
WARN execute{intent_id=8}: … Intent execution resulted in stuck accounts stuck_accounts=Some([BK91x…])
Committor DB, table
commit_status, row for the intent:commit_type=EmptyAccount commit_strategy=StateArgs undelegate=1 data=None lamports=2000000000
delegated_account_owner=MagicRootDRJ5atQjSJUxFjXzjeZXMADHUDznbk22gy
commit_status=FailedProcess retries_count=0
The delegation record on base says
owner = 11111111111111111111111111111111. The base transaction is[cu_limit, cu_price, commit_state, finalize, undelegate]; index 2 iscommit_state.Expected
The wallet's owner on base returns to the system program, as it did on
master.Root cause
magicblock-chainlink/src/cloner/mod.rs:127,undelegation_action, builds a genericMagicBlockInstruction::ScheduleIntentBundle. The engine runs it as aMagicRootInstruction::PostFinalizeaction, so the Magic program sees a CPI from MagicRoot.programs/magicblock/src/magic_scheduled_base_intent.rs:601callsCommittedAccount::from_account_shared(pubkey, &account, context.parent_program_id)withparent_program_id = Some(MagicRoot).magicblock-core/src/intent/types.rs:57:account.owner = parent_program_id.unwrap_or(account.owner);sets the owner to MagicRoot.magicblock-committor-service/src/tasks/commit_task.rs:57passescommitted_account.account.ownertodlp_api::instruction_builder::commit_state, which derives the program-config PDA from it.delegation_record.owner(src/processor/fast/commit_state.rs:238).dlp-api/src/requires.rs:604returnsDlpError::InvalidAuthority(0) on mismatch.Impact
Any delegation whose actions fail leaves the account under dlp on base, and the user cannot recover it without the validator key. The committor's error mapper has no case for
Custom(0)on a commit task, so there is no retry, and the startup replay reuses the stored MagicRoot owner and fails the same way.