custom program error: 0xb

Error·3 min read

custom program error: 0xb

The account you are closing is not empty. Almost always a fraction too small for your wallet to display, left behind by a partial fill or a rounding remainder.

Error 11, written 0xb in hex, is NonNativeHasBalance. The token program states it plainly: a non-native account can only be closed if its balance is zero. You are trying to close an account that still holds something.

But my wallet shows zero

It shows a rounded number. Balances are stored as integers in the mint's smallest unit, and a wallet displaying four or six decimals will render 0.0000001 of a token as 0.00. The account is not empty; it is empty-looking.

That remainder is dust, and it comes from ordinary activity: partial fills, a swap that routed slightly differently than quoted, rounding on a transfer, or an airdrop you never touched. Check the raw amount on a block explorer and you will usually see a long tail of digits where your wallet showed nothing.

The two ways out

Swap the remainder. If the token still trades, sell the dust for SOL. This keeps whatever value is left and empties the account in the same move. It only works when a route exists, and for most dead tokens it does not.

Burn the remainder. The burn instruction destroys the tokens and leaves the account at a true zero, after which the close succeeds. Irreversible, so it is right for junk and wrong for anything you have not identified.

Which one pays is a narrower question than it looks, because a swap on a thin pool can cost more than it returns. Burn or swap sets out the arithmetic, including the price impact and Token-2022 transfer fees that eat into the result.

Doing it from the command line

Two instructions, in this order. Burn what is left, then close the account and receive the rent deposit back:

spl-token burn <TOKEN_ACCOUNT> ALL
spl-token close --address <TOKEN_ACCOUNT>

For one or two accounts this is the cheapest route there is. It stops being practical somewhere around a dozen, which is where batching into fewer transactions starts to matter more than the per-account effort. The three routes compares them.

It still fails after burning

Three possibilities, in order of likelihood.

Withheld transfer fees. On a Token-2022 mint, fees withheld on transfer sit inside the account and block the close even at a zero balance. That surfaces as 0x23, and harvesting them to the mint clears it.

The account is frozen and still holds a balance. A frozen account closes fine at zero, but freezing blocks the burn you would need to get there. Only the token's freeze authority can lift that.

Close authority was delegated. Every token account has a close authority, which is the owner by default but can be reassigned. If it points elsewhere, only that address can close the account. What you cannot reclaim covers this and the other dead ends.

One exception worth knowing

Wrapped SOL is the case where a balance does not block the close. A wSOL account can be closed while it still holds SOL, because the underlying lamports are returned to you as part of closing it. Never burn wSOL to empty it first.