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 createHarvestWithheldTokensToMintInstruction before createCloseAccountInstruction.

SPL Token vs Token-2022

FeatureSPL Token (Legacy)Token-2022
CompatibilityMaximumBackward-compatible
Transfer hooksNoYes
Confidential transfersNoYes
Transfer fees / royaltiesNoYes
Metadata extensionsLimitedRich & extensible
Authority controlsBasicAdvanced
Best useSimple tokensProgrammable / 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

  1. Detect if the mint uses the Transfer Fee Extension.
  2. Include harvest only for matching accounts with the transfer-fee extension; do not apply it to every Token-2022 account.
  3. Harvest to the mint’s withheld balance; this is not withdrawal to a fee recipient.
  4. Issue createCloseAccountInstruction for the now-zeroed accounts.
  5. Confirm the close transaction and check its specified SOL destination.

Tools & Links

Token-2022 Transfer Fee docs

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.