Ошибка: Exit code 9 — Cell underflow

Причина и решение ошибки exit code 9 (cell underflow) при чтении slice/cell в TON.

Exit code 9 — Cell underflow

Compute phase: из slice прочитали больше бит или ссылок, чем в нём осталось. Почти всегда — рассинхрон layout при parse сообщения или storage.


Причина

  • load_uint(32) / loadRef(), а в cell этих данных нет;
  • другой контракт шлёт другой TL-B layout, чем ты парсишь;
  • забыли skip_bits / opcode перед полями;
  • прочитали ref как данные или наоборот.

Решение

func (fallback highlight)
() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {
    if (in_msg_body.slice_empty?()) { ;; пустое body — не читай дальше
        return ();
    }
    int op = in_msg_body~load_uint(32);
    int query_id = in_msg_body~load_uint(64);

    if (op == 0x12345678) {
        ;; сверяй остаток перед каждым load
        throw_unless(9, in_msg_body.slice_bits() >= 128);
        int amount = in_msg_body~load_coins();
        slice dest = in_msg_body~load_msg_addr();
        ;; ...
    }
}
tact (fallback highlight)
// Tact 1.6+ — типизированный receiver вместо ручного load
message Transfer {
    queryId: Int as uint64;
    amount: Int as coins;
}

contract SafeParse {
    receive(msg: Transfer) {
        // Tact сам проверяет layout; underflow уходит на этап decode
        require(msg.amount > 0, "amount");
    }
}

Как избежать в будущем

Фиксируй TL-B / message-структуры с обеих сторон. Перед ручным load_* проверяй slice_bits() / slice_refs(). В Tact предпочитай typed message, а не slice.

Материалы gramdocs.tech носят образовательный характер и не являются финансовой, юридической или инвестиционной рекомендацией. Работа с блокчейном TON и токеном Gram связана с рисками потери средств. Правовая информация