The transaction failed. You open it in the explorer, scroll to the program logs to find the error, and the logs stop mid-flow with two words: Log truncated. The error, if the program printed one, is somewhere in the part you cannot see.
The limit is small, it is applied in a way that drops more than you expect, and it applies to simulation too, which is why “I’ll just simulate it and read the logs” does not work either. Here are the rules, from the log collector, and what logging costs you in compute so you can stop paying for the lines that get cut.
The limit, and the way it is applied
Every transaction’s program logs go into one collector with a byte budget of 10,000 — ten thousand, decimal, not ten kibibytes. Each line a program emits is counted against it.
The check runs before a line is stored: if the bytes already written are at or above the limit, the line is dropped. The comparison is >=, not >, with a consequence that is often missed: the line that would cross the limit is not cut short to fit — it is dropped whole, and so is every line after it. Then the collector appends its own line, “Log truncated”, once, and stops.
The collector’s own test spells out the arithmetic: 20,000 attempts to write a one-byte line produce exactly 9,999 stored lines, then the marker. A program that logs a 2,000-byte line at byte 9,000 loses the whole line.
Simulation is capped too
The natural workaround — simulate the transaction and read the full logs — does not work, because the simulation path uses the same collector with the same default. The runtime’s simulation entry point passes “no limit” to the collector constructor, but “no limit” at that layer means “use the default”, and the default is 10,000.
There is exactly one way to construct an unlimited collector, and nothing in the validator calls it. Full logs are not available through any RPC on any public node.
Worth knowing: the limit is a per-validator flag. An operator can raise --log-messages-bytes-limit on their node, which means the same transaction can return different logs from different RPC endpoints. If your provider’s node has raised it, you will see more; if yours is truncated and a friend’s is not, that is why.
Where the full logs actually go
Every line the collector receives is also emitted through the validator’s ordinary logging at debug level, under a target named stable_log, before the byte budget is applied. An operator running a node at debug verbosity for that target sees the untruncated stream in the node’s log file — the one place the limit does not reach.
That is not a feature you can use from a wallet or an explorer. It is a reason to run your own node for debugging, or to ask your provider whether they can.
One more way a line goes missing, unrelated to the budget: the logging macro the runtime uses tries to borrow the collector, and if the collector is already borrowed at that moment, the line is silently dropped with no marker at all. It is rare and it is non-deterministic, which is the worst kind of missing log.
What each log line costs you
Logging is not free, and the cost is charged whether or not the line survives the budget.
msg! with a string — the sol_log_ syscall — costs the larger of 100 compute units and the string’s length in bytes. A 40-character message costs 100; a 4,000-byte dump of an account costs 4,000.
Logging a number (sol_log_64) costs 100. Logging a public key (sol_log_pubkey) costs 100.
sol_log_data, the structured variant, costs 100 × (1 + number of fields) plus the total bytes — so three 32-byte fields cost 100 × 4 + 96 = 496.
A program that logs generously can spend a meaningful fraction of its compute budget on lines nobody will see past byte 10,000. And because the leader ranks transactions by fee divided by requested compute, a bloated compute limit to cover logging also lowers your landing rank.
What to do instead
Log less, and log the thing that matters first. The error you need to read should be the first line, not the last.
Log bytes, not formatted strings. A formatted string of a struct is long; its discriminant and one or two fields are not.
Use return data for structured output. A program can set up to 1,024 bytes of return data that the RPC surfaces in simulation and transaction metadata, outside the log budget, and it is the right channel for “here is the result” rather than “here is a diary”.
Put the diagnostics behind a flag. A compile-time feature that enables verbose logging on devnet and strips it on mainnet costs nothing in production and keeps the budget for the line you need.
Log Truncation: Questions People Actually Ask
What does “Log truncated” mean on Solana?
The transaction’s program logs exceeded the 10,000-byte collector limit. The line that crossed the limit and every line after it were dropped, and the collector appended “Log truncated” once.
Why are my logs truncated in simulateTransaction too?
Simulation uses the same collector with the same default. “No limit” at the simulation entry point resolves to the 10,000-byte default, and no RPC path constructs an unlimited collector.
How much compute does msg! cost?
The larger of 100 compute units and the message length in bytes. Numbers and public keys cost 100 each; sol_log_data costs 100 per field plus one, plus the bytes.
Can I get the full logs anywhere?
On a node whose operator raised the per-validator log limit, or from the node’s own debug log, which receives every line before the budget applies. Neither is available from a standard public RPC.
The two numbers
Ten thousand bytes per transaction, applied as “drop the crossing line and everything after it”, in simulation as well as execution.
One hundred compute units minimum per line, rising with length, charged whether the line is kept or not.
The second number is the one you control.
A truncated log often hides the line that explains the failure, which is when the RPC error codes carry the rest of the diagnosis — and a simulation can be deliberately misleading even with complete logs. What each log call costs feeds straight into the leader’s ranking formula.
Constants read from the Agave validator source at commit beee69b958: svm-log-collector/src/lib.rs, syscalls/src/logging.rs and validator/src/commands/run/args.rs.