If you've built on Solana with Anchor, you've seen errors like
Error Code: 2003 with no clear explanation of what went wrong
or how to fix it.
This guide covers every official Anchor error code — what it
means, why it happens, and how to fix it.
How Anchor Error Codes Are Structured
Anchor errors follow a numbered system across 6 categories:
- 100–103 — Instruction errors
- 1000–1002 — IDL errors
- 1500 — Event errors
- 2000–2029 — Constraint errors (most common)
- 3000–3017 — Account errors
- 4000–4200 — State errors
Constraint Errors (2000–2029) — The Ones You'll Hit Most
2000 — ConstraintMut
Message: A mut constraint was violated
Cause: You're trying to modify an account not marked as mut
Fix: Add #[account(mut)] to the account in your instruction context
#[derive(Accounts)]
pub struct MyInstruction<'info> {
#[account(mut)] // <- add this
pub my_account: Account<'info, MyData>,
}
2001 — ConstraintHasOne
Message: A has_one constraint was violated
Cause: A field on your account doesn't match the expected pubkey
Fix: Make sure the account's field matches the signer or related account
#[account(has_one = authority)]
pub data_account: Account<'info, MyData>,
pub authority: Signer<'info>,
2002 — ConstraintSigner
Message: A signer constraint was violated
Cause: Account expected to sign but didn't
Fix: Ensure the account is a Signer type and the client passes it as a signer
2003 — ConstraintRaw
Message: A raw constraint was violated
Cause: Custom constraint expression evaluated to false
Fix: Debug your constraint = expression — add logs to check values
#[account(constraint = some_account.value > 0 @ MyError::InvalidValue)]
2006 — ConstraintOwner
Message: An owner constraint was violated
Cause: Account is owned by a different program than expected
Fix: Verify you're passing the correct account owned by your program
2012 — ConstraintSeeds
Message: A seeds constraint was violated
Cause: PDA address doesn't match the provided seeds + bump
Fix: Make sure seeds and bump on-chain match exactly what you used to derive the PDA client-side
// On-chain
#[account(seeds = [b"vault", user.key().as_ref()], bump)]
// Client-side — must match exactly
const [vault] = PublicKey.findProgramAddressSync(
[Buffer.from("vault"), user.publicKey.toBuffer()],
programId
)
Account Errors (3000–3017)
3000 — AccountDiscriminatorAlreadySet
Message: Account discriminator already set
Cause: Trying to initialize an account that's already initialized
Fix: Check if account exists before calling init instruction
3001 — AccountDiscriminatorNotFound
Message: Account discriminator not found
Cause: Account data is empty — account probably doesn't exist
Fix: Confirm the account is created and has data before fetching
3003 — AccountDidNotDeserialize
Message: Failed to deserialize the account
Cause: Account data doesn't match your struct layout
Fix: Check if the account was initialized with a different version of your program
3007 — AccountNotInitialized
Message: The given account is not initialized
Cause: Account has no data / wrong account passed
Fix: Make sure you're passing the right account address
3012 — AccountNotMutable
Message: The given account is not mutable
Cause: Trying to write to an account without marking it mutable
Fix: Pass the account with isMutable: true on the client side
Instruction Errors (100–103)
100 — InstructionMissing
Cause: 8-byte discriminator not found — wrong instruction or corrupted data
Fix: Verify you're calling the right instruction name
101 — InstructionFallbackNotFound
Cause: Fallback function called but not defined
102 — InstructionDidNotDeserialize
Cause: Instruction data couldn't be deserialized — argument mismatch
Fix: Check that client-side arguments match the instruction signature exactly
103 — InstructionDidNotSerialize
Cause: Return value couldn't be serialized
State Errors (4000–4200)
4000 — IdlInstructionStub
Cause: IDL instruction called but not implemented
4100 — EventInstructionStub
Cause: Event CPI called but handler not implemented
Quick Reference — Top 10 Errors
| Code | Name | One-Line Fix |
|---|---|---|
| 2000 | ConstraintMut | Add #[account(mut)]
|
| 2001 | ConstraintHasOne | Field must match related account pubkey |
| 2002 | ConstraintSigner | Account must sign the transaction |
| 2003 | ConstraintRaw | Custom constraint expression is false |
| 2006 | ConstraintOwner | Wrong program owns this account |
| 2012 | ConstraintSeeds | Seeds/bump mismatch between client and program |
| 3000 | AccountDiscriminatorAlreadySet | Account already initialized |
| 3001 | AccountDiscriminatorNotFound | Account doesn't exist yet |
| 3007 | AccountNotInitialized | Wrong account address passed |
| 3012 | AccountNotMutable | Pass account as mutable on client |
Full Reference PDF
This article covers the most common errors. I put together a
complete PDF handbook covering all 59 Anchor error codes with
full explanations, root causes, fixes, and code examples:
Anchor Error Handbook — Complete Reference (100–4200)
Useful if you want everything in one searchable document you
can keep open while building.
Top comments (0)