---
title: Common Gotchas
description: Avoid the highest-probability mistakes when implementing Thru C programs.
source_url:
  html: https://thru.org/docs/sdks/c-reference/common-gotchas/
  md: https://thru.org/docs/sdks/c-reference/common-gotchas.md
---

# Common Gotchas

Use this page when you want the shortest list of things most likely to break an implementation.

## 1. Treat `tsdk_return` and `tsdk_revert` as terminal

They both end execution through `tsys_exit`. Any code after them is unreachable.

## 2. Do not trust account indices from instruction payloads

Always run `tsdk_is_account_idx_valid(...)` before reading metadata, data pointers, or issuing syscalls with an account index taken from instruction bytes.

## 3. A data pointer is not the same thing as writable permission

`tsdk_get_account_data_ptr(...)` gives you an address, not permission. If you intend to mutate data, the account usually needs to be writable in context, and many flows should call `tsys_set_account_data_writable(...)` first.

## 4. `tsys_invoke` has two failure channels

Check both:

- the syscall return value
- the callee error in `invoke_err_code`

Ignoring one of them causes misleading CPI behavior.

## 5. Auth entries for CPI must be owned by the current program

The wrapper validates this before the syscall and can revert locally if you authorize an account your program does not own.

## 6. State proofs are variable-size

Do not use `sizeof( tsdk_state_proof_t )` as the received proof length. Read the header and call `tsdk_state_proof_footprint_from_header(...)`.

## 7. Transaction and proof structs are layout-sensitive

Several public structs are packed or represent wire-aligned layouts. Avoid casual casting from arbitrary byte buffers without checking size and alignment assumptions.

## 8. `tsdk_printf` is for debugging, not unlimited output

It formats into a fixed local buffer and ultimately logs through `tsys_log`.

## 9. Prefer helper accessors over manual VM address math

The segment constants and `TSDK_ADDR(...)` are public, but most tasks are safer with helpers like `tsdk_get_txn`, `tsdk_get_account_meta`, and `tsdk_get_current_block_ctx`.

## 10. Start with `tn_sdk.h` unless the task is clearly lower level

Agents can easily overcomplicate C SDK usage by pulling in too many low-level headers too early. The umbrella include is the right default.

## 11. Build against the installed SDK, not the repo-local SDK internals

For end-user workflows, prefer:

- `thru dev toolchain install`
- `thru dev sdk install c`
- `thru_c_program.mk`

not direct reliance on repo-local setup scripts.

## 12. Keep entrypoints thin

Large monolithic entrypoints make it harder for both humans and agents to reason about validation and mutation ordering. Validate early, dispatch quickly, and push real logic into helpers.
