Responsible team: Reclaim / MarketWhale · Reviewed:
Token-2022 Transfer Fees: Why Some Accounts Won't Close
Seeing "invalid account data for instruction" or the program log TransferFeeInstruction: HarvestWithheldTokensToMint? Token-2022 accounts that use the Transfer Fee Extension can only be closed when their withheld fees are zero. This guide explains the transfer-fee case; the same error can have other causes.
Quick Summary
- Token-2022 adds transfer hooks, metadata, and optional fees on top of the legacy SPL Token Program.
- With transfer fees enabled, each token account can accumulate withheld fee amounts.
- Closing fails with errors like "An account can only be closed if its withheld fee balance is zero"until those withheld fees are harvested to the mint.
- For accounts with the required transfer-fee extension, run
createHarvestWithheldTokensToMintInstructionbeforecreateCloseAccountInstruction.
SPL Token vs Token-2022
| Feature | SPL Token (Legacy) | Token-2022 |
|---|---|---|
| Compatibility | Maximum | Backward-compatible |
| Transfer hooks | No | Yes |
| Confidential transfers | No | Yes |
| Transfer fees / royalties | No | Yes |
| Metadata extensions | Limited | Rich & extensible |
| Authority controls | Basic | Advanced |
| Best use | Simple tokens | Programmable / compliant tokens |
Why Closing Fails
Token-2022 accounts with the Transfer Fee Extension track withheld fees inside each token account. A nonzero withheld balance prevents closure. An invalid-data error can also mean a wrong program ID, mint, or missing extension. Inspect the actual account and program logs, including invalid account data for instruction and "An account can only be closed if its withheld fee balance is zero".
Harvesting moves withheld tokens into the mint’s withheld balance. It does not withdraw them to your wallet. Withdrawal is a separate operation requiring the configured withdraw-withheld authority.
Fix: Harvest Then Close
Check that the mint and source account belong to Token-2022, the mint has TransferFeeConfig, and the source has TransferFeeAmount. The source must belong to that mint and have zero ordinary token balance. The example builds instructions using @solana/spl-token 0.4.x; the public keys and authorized signer must be supplied by your application.
import {
TOKEN_2022_PROGRAM_ID,
createHarvestWithheldTokensToMintInstruction,
createCloseAccountInstruction,
} from "@solana/spl-token";
const harvestIx = createHarvestWithheldTokensToMintInstruction(
mintPubkey,
[tokenAccount],
TOKEN_2022_PROGRAM_ID
);
const closeIx = createCloseAccountInstruction(
tokenAccount,
destinationWallet,
authority,
[],
TOKEN_2022_PROGRAM_ID
);
// Add harvestIx then closeIx to a transaction.
// The fee payer and account close authority must sign.
// Simulate before sending; inspect confirmation and program logs.
Harvesting addresses withheld transfer fees only. Closure can still fail because of an incorrect close authority, other extension requirements, a changed balance, or transaction errors. The presence of HarvestWithheldTokensToMint in a log is not itself an error diagnosis.
Workflow to Avoid Errors
- Detect if the mint uses the Transfer Fee Extension.
- Include harvest only for matching accounts with the transfer-fee extension; do not apply it to every Token-2022 account.
- Harvest to the mint’s withheld balance; this is not withdrawal to a fee recipient.
- Issue
createCloseAccountInstructionfor the now-zeroed accounts. - Confirm the close transaction and check its specified SOL destination.
Tools & Links
Reclaim SOL detects transfer-fee extensions and prepares harvest before close. This handles that extension’s withheld-balance condition, but does not guarantee all Token-2022 accounts will close.
Review Reclaim’s fees and eligibility before signing. A zero token balance in the scan is a candidate for closure, not proof that every extension and authority check will pass.
See the Reclaim fees and eligibility reference and Solana close-account documentation.
Keep learning
How to Close Token Accounts on Solana