{"record":{"id":"b7e197f8e9da5e86","repo":"linera-io/linera-protocol","slug":"invalid-block-export-configuration-message","errorCode":null,"errorMessage":"invalid block export configuration: {message}","messagePattern":"invalid block export configuration: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"linera-core/src/chain_worker/export.rs","lineNumber":535,"sourceCode":"/// Spawns the process-wide export queue task and returns the handle chain workers push to.\n///\n/// The task runs until every clone of the returned handle is dropped, and reads only from\n/// `storage` — never through a chain worker, whose TTL a touch would reset.\npub fn spawn_block_export_queue<S, P>(\n    storage: S,\n    node_provider: Arc<P>,\n    config: BlockExportConfig,\n    own_public_key: Option<ValidatorPublicKey>,\n) -> BlockExportHandle\nwhere\n    S: Storage + Clone + Send + Sync + 'static,\n    P: ValidatorNodeProvider + Send + Sync + 'static,\n    P::Node: Send + Sync,\n{\n    // Enforced here rather than only at the CLI: every constructor, tests included, must go\n    // through it, and an invalid config panics at startup instead of mid-export.\n    if let Err(message) = config.check() {\n        panic!(\"invalid block export configuration: {message}\");\n    }\n    let (blocks, receiver) = mpsc::channel(config.queue_size);\n    let progress: SharedProgress = Arc::default();\n    let tips: SharedTips = Arc::default();\n    let queued_bytes = Arc::new(std::sync::atomic::AtomicUsize::new(0));\n    let queue_bytes_budget = config.queue_bytes;\n    let max_in_flight_total = config.max_in_flight_total;\n\n    let task = BlockExportQueue {\n        storage,\n        node_provider,\n        config,\n        own_public_key,\n        latest_epoch: None,\n        committee: None,\n        committee_dirty: false,\n        admin_chain_id: None,\n        ticks_until_scan: 0,","sourceCodeStart":517,"sourceCodeEnd":553,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-core/src/chain_worker/export.rs#L517-L553","documentation":"spawn_block_export_queue is the single entry point for the block-export pipeline and runs BlockExportConfig::check() first, panicking with the failed rule's message if the config is invalid. This is a deliberate fail-fast: every constructor (CLI, tests, programmatic) must pass a sane config, and misconfiguration aborts at startup rather than corrupting an export mid-run.","triggerScenarios":"Any BlockExportConfig with a zero limit or inverted bounds reaches spawn: certificate_upload_batch_size == 0, queue_size == 0, queue_bytes == 0, max_in_flight_per_destination == 0, max_in_flight_total == 0, max_in_flight_total < max_in_flight_per_destination, max_catch_up_blocks == 0, or a zero idle_catch_up_interval. Typical sources: a config file missing fields that deserialize to 0, manual construction in tests, or CLI overrides zeroing a value.","commonSituations":"Hand-rolled configs in tests that only set a few fields; config files from an older/newer version missing newer knobs (defaulting to 0); scripts copying a partial config template; 'disable this feature by setting it to 0' assumptions colliding with the validator.","solutions":["Read the panic message — it names the exact field and rule (e.g. 'block export queue size must be greater than zero'); fix that field.","Prefer deriving from the defaults (queue_size 1024, queue_bytes 256 MiB, …) and overriding individual fields instead of constructing from scratch.","If constructing configs programmatically, run config.check()? yourself first and surface the error instead of panicking."],"exampleFix":"// before\nlet config = BlockExportConfig { queue_size: 0, ..Default::default() };\nspawn_block_export_queue(config, ...); // panics\n\n// after\nlet config = BlockExportConfig { ..Default::default() }; // queue_size = 1024\nconfig.check()?; // surface a Result, don't panic\nspawn_block_export_queue(config, ...);","handlingStrategy":"validation","validationCode":"// Rust\nlet mut config = BlockExportConfig::default(); // sane baseline (queue_size 1024, queue_bytes 256 MiB, ...)\n// apply overrides, then:\nif let Err(msg) = config.check() {\n    return Err(format!(\"invalid block export configuration: {msg}\"));\n}\nspawn_block_export_queue(config, ...);","typeGuard":"fn valid_export_config(config: &BlockExportConfig) -> bool { config.check().is_ok() }","tryCatchPattern":null,"preventionTips":["Never construct BlockExportConfig from scratch with ..Default::default() blind spots; start from default() and override explicitly.","Run config.check() in config-loading code (CLI, tests) and surface the message instead of letting the spawn panic.","Watch for deserialized configs with missing fields defaulting to 0 — the zero values are exactly what check() rejects."],"tags":["rust","configuration","block-export","panic","startup-validation"],"backgroundTag":"invalid-configuration","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}