TeachMeBitcoin

Error: stack underflow — OP_ADD requires 2 items

From TeachMeBitcoin, the free encyclopedia Reading time: 3 min

7. Common Script Execution Errors

OP_RETURN in Execution Path

OP_RETURN immediately marks the script as invalid when encountered in the execution path. This is different from OP_RETURN appearing in an OP_IF/OP_ENDIF branch that is not taken. Any script that reaches OP_RETURN during active execution fails.

Error: Script failed — OP_RETURN encountered

Stack Underflow

Every opcode that pops items requires a sufficient stack depth. If you call OP_ADD with fewer than 2 items on the stack, execution fails:

btcdeb '[OP_1 OP_ADD]'
# Error: stack underflow — OP_ADD requires 2 items

Mitigation: carefully count push and pop operations before each consuming opcode.

OP_EQUALVERIFY Failure

If the two top stack items are not equal, OP_EQUALVERIFY causes an immediate failure. The most common cause in P2PKH is providing a public key whose hash does not match the hash embedded in the scriptPubKey:

Error: Script failed — OP_EQUALVERIFY: stack top items not equal

Debug steps:

  1. Verify you are hashing the correct (compressed vs. uncompressed) public key.

  2. Confirm the hash in the scriptPubKey matches your key format.

  3. Use btcdeb to inspect the stack at step 4 of P2PKH execution.

OP_CHECKSIG Failure

OP_CHECKSIG returns 0 (false) rather than causing an immediate error, but a 0 result will ultimately cause the script to fail. Common causes:

  • Signature covers wrong data: The signature must commit to the correct serialization of the transaction (sighash preimage). Any mismatch in inputs, outputs, or sighash type causes failure.

  • Wrong sighash type: The sighash byte appended to the signature must match what was signed.

  • Non-canonical DER encoding: Pre-BIP66, non-canonical DER signatures were accepted. Post-BIP66, they are rejected.

  • Compressed vs. uncompressed key mismatch: In P2PKH, the key in the scriptSig must be in the same format (compressed/uncompressed) that was used when deriving the address.

# Check if a signature is low-S (BIP62 compliant)
from ecdsa.numbertheory import inverse_mod

def is_low_s(signature_hex: str, order: int) -> bool:
    sig = bytes.fromhex(signature_hex)
    # Parse S from DER: skip 30 <len> 02 <r_len> <R bytes> 02 <s_len>
    r_len = sig[3]
    s_len = sig[5 + r_len]
    s_start = 6 + r_len
    S = int.from_bytes(sig[s_start:s_start+s_len], 'big')
    return S <= order // 2

OP_CHECKMULTISIG Off-by-One Bug

Due to a historical bug, OP_CHECKMULTISIG pops one extra item off the stack (beyond the signatures and keys). This is why all P2SH multisig scriptSigs begin with OP_0. Forgetting this causes a stack underflow.

Non-Minimal Push Encoding (BIP62/BIP141)

SegWit introduced stricter rules requiring minimal push encoding. For example:

  • Pushing an empty byte array must use OP_0, not OP_PUSHDATA1 0x00.

  • Pushing a 1-byte value 0x010x10 must use OP_1OP_16, not a 1-byte data push.

Violating these rules in SegWit scripts causes validation failure even if the logic is correct:

Error: mandatory-script-verify-flag-failed (Data push larger than necessary)

Pro Tip

When debugging scripts, always start with a high-level disassembly before diving into the stack trace. Tools like bitcoin-cli decodescript are your first line of defense in identifying standard script patterns.

☕ Help support TeachMeBitcoin

TeachMeBitcoin is an ad-free, open-source educational repository curated by a passionate team of Bitcoin researchers and educators for public benefit. If you found our articles helpful, please consider supporting our hosting and ongoing content updates with a clean donation:

Ethereum: 0x578417C51783663D8A6A811B3544E1f779D39A85
Bitcoin: bc1q77k9e95rn669kpzyjr8ke9w95zhk7pa5s63qzz
Solana: 4ycT2ayqeMucixj3wS8Ay8Tq9NRDYRPKYbj3UGESyQ4J
Address copied to clipboard!