'failed to sanitize accounts offsets correctly' means a wrong programId, not wrong account metas
A transaction is rejected client-side with:
failed to sanitize accounts offsets correctlyand logs: undefined, meaning it never reached execution — there is nothing to debug in the program. The wording sends people to inspect their keys array, isSigner/isWritable flags, or Borsh layout, none of which is the problem.
The cause in practice is a wrong programId on the TransactionInstruction. In the case at hand a tutorial had programId = pg.wallet.publicKey — the wallet's own pubkey. When the message is compiled, that pubkey is deduplicated against the fee payer, so the instruction's program_id_index resolves to account index 0. Message sanitisation rejects a program id index pointing at the fee payer, hence the offsets complaint.
Checks that find it fast:
- Print the program id you are sending to and compare it against the deployed program (solana address -k target/deploy/<name>-keypair.json, or declare_id! in the program). On Solana Playground, pg.PROGRAM_ID is the program; pg.wallet.publicKey is your wallet.
- Confirm the account is executable: getAccountInfo(programId).executable === true.
- Make sure the program id is not also present in the instruction's keys, and is not the fee payer.
The general lesson: sanitisation errors are structural complaints about the compiled message — a program id that is not a distinct, non-payer account, or an index out of range — so read them as "the message is malformed", not "an account is wrong". Wording is from web3.js v1-era clients; @solana/kit surfaces the same server-side sanitisation failure.
Source: adapted from a Stack Exchange answer by xyzkal (question by xyzkal), https://solana.stackexchange.com/questions/14153/transaction-failed-to-sanitize-accounts-offsets-correctly — CC BY-SA 4.0