1. API reference

Errors

Every carbon_core::error::Error variant in Carbon 2.0.0 with its message, cause and fix, plus common errors from RPC, rustls and Cargo.

On this page

This page lists every variant of carbon_core::error::Error in Carbon 2.0.0 as error → cause → fix, followed by errors that come from Carbon's dependencies but show up in Carbon pipelines. For how errors flow through a pipeline, see Error handling.

Source: crates/core/src/error.rs.

How Carbon reports errors#

Rust
#[derive(Error, Debug)]
pub enum Error {
    #[error("Missing update type in datasource")]
    MissingUpdateTypeInDatasource(UpdateType),
    #[error("Failed to receive updates({0})")]
    FailedToReceiveUpdates(String),
    #[error("Transaction missing fee payer")]
    MissingFeePayer,
    #[error("Missing inner instructions")]
    MissingInnerInstructions,
    #[error("Missing account in transaction")]
    MissingAccountInTransaction,
    #[error("Missing instruction data")]
    MissingInstructionData,
    #[error("Failed to consume datasource ({0})")]
    FailedToConsumeDatasource(String),
    #[error("Custom error: {0}")]
    Custom(String),
}

pub type CarbonResult<T> = Result<T, Error>;

The pipeline logs errors with {:?}, so logs show the Debug form (FailedToConsumeDatasource("Failed to fetch program accounts")), not the Display message. Both forms are listed below. Where an error surfaces decides what happens next:

Where it is returnedLog line (error level, target carbon_core::pipeline)Effect
Datasource::consumeerror consuming datasource: <Debug>That datasource stops. The others keep running. When none are left, the pipeline drains the channel and run returns Ok(()).
A decoder step or Processor::processerror processing update (<update Debug>): <Debug>The update is counted in carbon_updates_failed_total; the remaining pipes for that update are skipped; processing continues.
A metrics exporternonePipeline::run returns the error.

Enable logs with a logger such as env_logger and RUST_LOG=info (Carbon's own messages are at info, warn and error).

FailedToConsumeDatasource#

Error. Failed to consume datasource (<message>). Logged as error consuming datasource: FailedToConsumeDatasource("<message>").

Cause. A datasource's consume could not start or continue. Built-in producers and their messages:

DatasourceMessages
RPC GPAFailed to fetch program accounts (any RPC or deserialization failure of getProgramAccounts, including rate limits and timeouts); Failed to parse pubkey: …; Failed to decode account
Helius GPA V2HTTP request failed: …, Failed to parse response: …, RPC error: <message> (code: <code>), Response missing context or value field
Helius GTFAFailed to serialize request config: …, HTTP request failed: …, HTTP error <status>: <body>, Failed to parse response: …, RPC error: <message> (code: <code>), Response missing result field
Yellowstone gRPC, Helius LaserStreamThe tonic or client error text when building the endpoint, setting x_token, or connecting (invalid URL, DNS, TLS, refused connection, bad token)
Validator snapshotLedger directory does not exist: …, Genesis archive not found: …. Expected genesis.tar.bz2, No loadable full snapshot archive found in …, Failed to load bank forks from snapshot: …, Invalid snapshot: loaded bank has slot 0, …, download errors such as Failed to download <url> after 3 retries: …, Scan failed: …

Fix. Read the message after the variant name; it names the failing step.

  1. For connection errors, check the endpoint URL and scheme (https:// for TLS gRPC), the token, and network access.
  2. For Failed to fetch program accounts on the public endpoint, add filters (such as a dataSize or memcmp on the discriminator) to RpcProgramAccountsConfig: unfiltered getProgramAccounts on large programs times out or is rejected. Use a paid RPC for large programs.
  3. For snapshot errors, check the paths and that the archive matches the cluster.
  4. Restart the pipeline, or wrap the datasource in your own retry loop: datasources don't restart themselves after consume returns.

See also. Datasources, Load account state, Load a snapshot.

Custom#

Error. Custom error: <message>. Logged as Custom("<message>").

Cause. A catch-all used by:

ProducerMessage
RPC block subscribeFailed to create RPC subscribe client after 10 attempts: …, Failed to subscribe after 10 attempts: …
RPC program subscribeFailed to create RPC subscribe client after 10 attempts: …, Failed to subscribe after 10 attempts: …
Helius Atlas WebSocketError creating Filters for the Helius WebSocket: accounts and transactions can't be both empty, Failed to create Helius client after … attempts: …
carbon_core::postgres and generated Postgres codeThe sqlx error text, or out of range, invalid numeric string, value exceeds maximum for target type, invalid scale for i128, invalid sign/scale for unsigned integer
Your codeAnything you wrap, for example Error::Custom(e.to_string())

The subscribe datasources wait 3 seconds between attempts.

Fix. For subscribe failures, read the wrapped error: Method not found (-32601) means the endpoint doesn't support the method (see blockSubscribe is not supported); connection errors mean a wrong wss:// URL or a blocked network. For Atlas, pass at least one account or transaction filter. For Postgres errors, see the Postgres reference. In your own code, prefer Custom with a descriptive message over unwrap, so the pipeline logs the failure and continues.

See also. Stream with RPC, Postgres.

MissingFeePayer#

Error. Transaction missing fee payer. Logged as error processing update (Transaction(…)): MissingFeePayer.

Cause. The pipeline converts each TransactionUpdate into TransactionMetadata and takes the fee payer from the first static account key of the message. The message has no account keys. Built-in datasources never send such transactions; it happens when a custom datasource builds a VersionedTransaction with an empty or default message.

Fix. Build TransactionUpdate::transaction from the full decoded transaction (for RPC, EncodedTransaction::decode() on a Base64 payload), not from VersionedTransaction::default(). The update is skipped and the pipeline continues.

See also. TransactionUpdate, Custom datasource.

MissingAccountInTransaction#

Error. Missing account in transaction. Logged as MissingAccountInTransaction.

Cause. Returned only by the public helper carbon_core::transformers::extract_account_metas(compiled_instruction, message) when an account index points past the message's static account keys. The pipeline does not call this helper. It happens when you call it on a V0 transaction whose instruction uses accounts from an address lookup table, because the helper ignores meta.loaded_addresses.

Fix. Use the instruction the pipeline already built (raw_instruction in instruction processors, or NestedInstruction::instruction), whose accounts include lookup-table addresses. If you need the helper, append meta.loaded_addresses.writable and readonly to the keys yourself.

See also. InstructionProcessorInputType.

MissingUpdateTypeInDatasource#

Error. Missing update type in datasource. Logged as MissingUpdateTypeInDatasource(<UpdateType>).

Cause. Nothing in Carbon 2.0.0 returns this variant. It is reserved for checking a datasource's update_types() against registered pipes, which the 2.0.0 pipeline does not do.

Fix. If you see it, it comes from your own code or a third-party crate; read that code. Carbon itself does not validate update_types().

See also. UpdateType.

FailedToReceiveUpdates#

Error. Failed to receive updates(<message>) (no space before the parenthesis). Logged as FailedToReceiveUpdates("<message>").

Cause. Not returned anywhere in Carbon 2.0.0. Available for custom datasources that lose their upstream stream.

Fix. Read the wrapped message from the datasource that returned it. If you write a datasource, either variant is fine; FailedToConsumeDatasource is what the built-in ones use.

See also. Datasource.

MissingInnerInstructions#

Error. Missing inner instructions. Logged as MissingInnerInstructions.

Cause. Not returned anywhere in Carbon 2.0.0. When meta.inner_instructions is None, the pipeline treats the transaction as having no CPIs instead of failing.

Fix. If CPIs are missing from your processors, the source did not send inner instructions: for custom RPC datasources, request transaction_details: Full; for Yellowstone, use a full transaction subscription. See also invalid inner instruction stack height.

See also. Instructions.

MissingInstructionData#

Error. Missing instruction data. Logged as MissingInstructionData.

Cause. Not returned anywhere in Carbon 2.0.0.

Fix. Read the code that returned it; decoders signal "not mine" by returning None, not this error.

See also. InstructionDecoder.

ConversionError#

Error. A separate error type, carbon_core::transformers::yellowstone::ConversionError (behind carbon-core's yellowstone feature). Its variants and Display messages:

Text
MissingField(field)                       missing required protobuf field `<field>`
InvalidByteLength { field, expected, actual }  invalid byte length for `<field>`: expected <expected>, got <actual>
IntegerOutOfRange { field, value }        value <value> for `<field>` does not fit in a u8
InvalidEnum { field, value }              invalid enum value <value> for `<field>`
InvalidNumber { field, value }            invalid numeric value `<value>` for `<field>`
InvalidTransactionError(_)                failed to decode the protobuf transaction error with wincode

Cause. The Yellowstone and LaserStream datasources convert protobuf transactions with create_tx_versioned and create_tx_meta. A malformed or incompatible message fails the conversion. They log Failed to create transaction meta: <Debug> and skip that transaction; a failed create_tx_versioned skips the transaction silently.

Fix. Usually a server running a Yellowstone protocol version that doesn't match yellowstone-grpc-proto 12.7 (Carbon 2.0.0's pin). Check the provider's version. The pipeline continues with the next transaction.

See also. Stream with Yellowstone.

These errors don't come from carbon_core::error::Error, but readers hit them while running Carbon pipelines.

Method not found for blockSubscribe#

Error. With RpcBlockSubscribe on wss://api.mainnet-beta.solana.com:

Text
[2026-11-09T00:15:41Z ERROR carbon_rpc_block_subscribe_datasource] Failed to subscribe to block updates: SubscribeFailed { reason: "Method not found (-32601)", message: "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32601,\"message\":\"Method not found\"},\"id\":1}" }
[2026-11-09T00:16:42Z ERROR carbon_core::pipeline] error consuming datasource: Custom("Failed to subscribe after 10 attempts: subscribe failed: Method not found (-32601)")
[2026-11-09T00:16:42Z INFO  carbon_core::pipeline] update_receiver closed, shutting down.
[2026-11-09T00:16:42Z INFO  carbon_core::pipeline] pipeline shutdown complete.

Cause. blockSubscribe is an unstable RPC method that validators only serve with --rpc-pubsub-enable-block-subscription. Solana's public endpoints don't enable it. The datasource retries 11 times, 3 seconds apart, then gives up, and the pipeline exits with status 0.

Fix. Use an RPC provider that supports blockSubscribe, or switch datasource: the RPC transaction crawler works on the public endpoint for one program's history, and Yellowstone gRPC or Helius LaserStream stream every block.

See also. Stream with RPC.

429 Too Many Requests#

Error. With the RPC transaction crawler (or GPA) on the public endpoint, at RUST_LOG=debug:

Text
[2026-11-09T00:18:44Z DEBUG solana_rpc_client::http_sender] Too many requests: server responded with Response { url: "https://api.mainnet-beta.solana.com/", status: 429, headers: {…, "retry-after": "10", …} }

and, once the client's own retries are exhausted, at warn and error level:

Text
[2026-11-09T00:19:39Z WARN  carbon_rpc_transaction_crawler_datasource] Failed to fetch transaction 2RPWo3shvDtwGNSD2tY79uwFJ6Gbx1M7g5knfsJEDpcdahojCL8csGJV6KCEyvzZC2UhBnctSPcFSwSPr4i4jHct (attempt 1/3), retrying in 1000ms: Error { request: Some(GetTransaction), kind: Reqwest(reqwest::Error { kind: Status(429, None), url: "https://api.mainnet-beta.solana.com/" }) }

Cause. The public endpoint rate-limits per IP. solana-rpc-client retries 429s internally (logged at debug), then the crawler retries with backoff (RetryConfig::default(): 3 retries, 1 s initial, ×2, 10 s max). After the last retry it logs Failed to fetch transaction <sig> after 3 retries: … and skips that transaction.

Fix.

  1. Lower ConnectionConfig::max_concurrent_requests (default 5) and raise polling_interval.
  2. Raise RetryConfig::max_retries and the backoff so fewer transactions are skipped.
  3. For anything beyond a demo, use a paid RPC endpoint.

See also. Backfill transactions, RPC transaction crawler.

Could not automatically determine the process-level CryptoProvider#

Error. At startup, with the Yellowstone gRPC or Helius LaserStream datasource and a TLS (https://) endpoint:

Text
thread 'tokio-rt-worker' panicked at /home/you/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rustls-0.23.46/src/crypto/mod.rs:249:14:

Could not automatically determine the process-level CryptoProvider from Rustls crate features.
Call CryptoProvider::install_default() before this point to select a provider manually, or make sure exactly one of the 'aws-lc-rs' and 'ring' features is enabled.
See the documentation of the CryptoProvider type for more information.

[2026-11-09T00:51:58Z INFO  carbon_core::pipeline] update_receiver closed, shutting down.
[2026-11-09T00:51:58Z INFO  carbon_core::pipeline] pipeline shutdown complete.

Cause. The gRPC stack pulls in rustls 0.23 with both the ring and aws-lc-rs backends, so rustls can't pick one. The panic happens inside the datasource's task, so the pipeline logs a clean shutdown and exits with status 0.

Fix. Install a provider once at the start of main, before building the datasource:

Cargo.toml
[dependencies]
rustls = { version = "0.23", default-features = false, features = ["aws-lc-rs"] }
src/main.rs
rustls::crypto::aws_lc_rs::default_provider()
    .install_default()
    .expect("failed to install the rustls crypto provider");

See also. Stream with Yellowstone, Stream with LaserStream.

there are multiple different versions of crate carbon_core#

Error. At compile time, when a Carbon 1.x crate is mixed with Carbon 2.0.0:

Text
error[E0277]: the trait bound `for<'a> MemoProgramDecoder: InstructionDecoder<'a>` is not satisfied
   --> src/main.rs:19:53
    |
 19 |     let _pipeline = Pipeline::builder().instruction(MemoProgramDecoder, Memos).build()?;
    |                                         ----------- ^^^^^^^^^^^^^^^^^^ the trait `for<'a> InstructionDecoder<'a>` is not implemented for `MemoProgramDecoder`
    |                                         |
    |                                         required by a bound introduced by this call
    |
note: there are multiple different versions of crate `carbon_core` in the dependency graph
   --> /home/you/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/carbon-core-2.0.0/src/instruction.rs:187:1
    |
187 | pub trait InstructionDecoder<'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this is the expected trait
    |
   ::: /home/you/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/carbon-core-1.0.0/src/instruction.rs:188:1
    |
188 | pub trait InstructionDecoder<'a> {
    | -------------------------------- this is the found trait

Cause. Here carbon-memo-program-decoder = "1.0.0" sits next to carbon-core = "2.0.0", so two carbon_core crates are compiled and the decoder implements the 1.x trait. The same happens with Solana types: Carbon 1 uses the Solana 3 crates (solana-account 3, solana-transaction-status 3) and Carbon 2 the Agave 4.2 cohort (solana-account 4.3, solana-transaction-status 4.2), so you get expected Account, found a different Account with a "multiple different versions of crate solana_account" note. Pubkey is the exception: solana-pubkey 3 and 4 are the same type, so pubkeys don't trigger it.

Fix.

  1. Set every Carbon crate in Cargo.toml to 2.0.0.
  2. Set direct Solana dependencies to the versions Carbon 2.0.0 pins (for example solana-account = "4.3.2", solana-instruction = "3.4.1", solana-pubkey = "4.2.1", solana-client = "=4.2.2").
  3. Find the stray crate with cargo tree -i carbon-core@1.0.0 (or -i solana-account@3.0.0).
  4. Regenerate decoders produced by an older CLI with @sevenlabs-hq/carbon-cli@2.0.0. carbon-jetstreamer-datasource and carbon-jito-shredstream-grpc-datasource have no 2.0 release; don't use them with Carbon 2.

See also. Migrate to v2, Installation.

Failed to decode transaction with Json encoding#

Error. With RpcBlockSubscribe or RpcBlockCrawler configured with UiTransactionEncoding::Json or JsonParsed, every transaction logs:

Text
ERROR carbon_rpc_block_subscribe_datasource] Failed to decode transaction: EncodedTransactionWithStatusMeta { transaction: Json(UiTransaction { … }), … }

Cause. Carbon rebuilds the binary transaction with EncodedTransaction::decode(), which only works for binary encodings. JSON payloads can't be decoded, so each transaction is skipped and no instruction processor runs.

Fix. Request a binary encoding and V1 support in the config you pass:

Rust
RpcBlockSubscribeConfig {
    encoding: Some(UiTransactionEncoding::Base64),
    transaction_details: Some(TransactionDetails::Full),
    max_supported_transaction_version: Some(1),
    ..RpcBlockSubscribeConfig::default()
}

Use the same fields on RpcBlockConfig for the block crawler. The transaction crawler and Helius GTFA set Base64 and V1 themselves.

See also. Stream with RPC, Migrate to v2.

Full(..) when sending updates#

Error. One of:

Text
ERROR carbon_yellowstone_grpc_datasource] Failed to send transaction update with signature … at slot …: "Full(..)"
WARN  carbon_rpc_transaction_crawler_datasource] Failed to send update: "Full(..)"
ERROR carbon_rpc_block_crawler_datasource] Error sending transaction update: "Full(..)"

Cause. The pipeline's update channel is full because processors are slower than the source, and the datasource uses try_send, which drops the update instead of waiting. Yellowstone, LaserStream, Helius Atlas, RPC block subscribe, RPC block crawler, RPC program subscribe and (by default) the RPC transaction crawler all drop updates this way. Block subscribe and block crawler also stop sending the rest of that block.

Fix.

  1. Raise channel_buffer_size (default 1,000).
  2. Make processors faster, or move slow work (database writes, HTTP calls) to a spawned task or a batch.
  3. For the transaction crawler, set ConnectionConfig::blocking_send = true to apply backpressure instead of dropping.
  4. Watch the carbon_updates_queued gauge.

See also. Production, Metrics reference.

Invalid inner instruction stack height#

Error.

Text
WARN  carbon_core::transformers] invalid inner instruction stack height (None) in transaction <signature> at instruction <index>, dropping the remaining inner instructions of this group

Cause. The source sent inner instructions without a stack_height (old transactions, or providers that strip it), or with a height outside 2 to 5. Carbon needs the height to rebuild the CPI tree, so it drops the rest of that instruction's inner instructions. Their instruction processors don't run.

Fix. Use a source that reports stackHeight (current RPC nodes and Yellowstone do). For historical data from before stack heights were recorded, decode inner instructions yourself from meta.inner_instructions in a transaction processor.

See also. Instructions.

Ctrl-C does not stop the pipeline#

Error. The process keeps running after Ctrl-C, usually under load.

Cause. Pipeline::run only listens for Ctrl-C between updates and installs a handler that replaces the default exit, so a signal that arrives while a processor runs is lost.

Fix. Handle Ctrl-C yourself and cancel a token passed to datasource_cancellation_token. See Ctrl-C is ignored while an update is processing.

See also. Shutdown.

Your endpoints

Code samples use these instead of the placeholders, so you can copy and run them as they are. They’re stored only in this browser and never sent anywhere.