linera-io/linera-protocol · error · anyhow

We should have one, two or three parts

Error message

We should have one, two or three parts

What it means

Raised while parsing a `rocksdb:` storage configuration in `StorageConfig::from_str` (linera-storage-runtime). After the prefix, the remainder is split on ':' and only 1 (directory), 2 (directory:spawn_mode), or 3 (directory:spawn_mode:namespace) parts are accepted; this bail fires for any other count (typically 4+ parts).

Source

Thrown at linera-storage-runtime/src/storage_config.rs:175

                    .expect("validated by the parts length check above");
                let spawn_mode = match spawn_mode_name {
                    "spawn_blocking" => Ok(RocksDbSpawnMode::SpawnBlocking),
                    "block_in_place" => Ok(RocksDbSpawnMode::BlockInPlace),
                    "runtime" => Ok(RocksDbSpawnMode::get_spawn_mode_from_runtime()),
                    _ => Err(anyhow!("Failed to parse {spawn_mode_name} as a spawn_mode")),
                }?;
                let namespace = if parts.len() == 2 {
                    DEFAULT_NAMESPACE.to_string()
                } else {
                    parts[2].to_string()
                };
                let inner_storage_config = InnerStorageConfig::RocksDb { path, spawn_mode };
                return Ok(StorageConfig {
                    inner_storage_config,
                    namespace,
                });
            }
            bail!("We should have one, two or three parts");
        }
        #[cfg(feature = "scylladb")]
        if let Some(s) = input.strip_prefix(SCYLLA_DB) {
            let mut uri: Option<String> = None;
            let mut namespace: Option<String> = None;
            let parse_error: &'static str = "Correct format is tcp:db_hostname:port.";
            if !s.is_empty() {
                let mut parts = s.split(':');
                while let Some(part) = parts.next() {
                    match part {
                        "tcp" => {
                            let address = parts.next().ok_or_else(|| {
                                anyhow!("Failed to find address for {s}. {parse_error}")
                            })?;
                            let port_str = parts.next().ok_or_else(|| {
                                anyhow!("Failed to find port for {s}. {parse_error}")
                            })?;
                            let port = NonZeroU16::from_str(port_str).map_err(|_| {

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Reduce to `rocksdb:<directory>`, `rocksdb:<directory>:<spawn_mode>`, or `rocksdb:<directory>:<spawn_mode>:<namespace>`
  2. Remove the extra colon-separated segment
  3. Use directory paths and namespaces without ':' characters

Example fix

# before
--storage rocksdb:/tmp/db:block_in_place:my_ns:extra

# after
--storage rocksdb:/tmp/db:block_in_place:my_ns
Defensive patterns

Strategy: validation

Validate before calling

// Rust: pre-validate a rocksdb storage string before FromStr
fn is_valid_rocksdb_config(s: &str) -> bool {
    let Some(rest) = s.strip_prefix("rocksdb:") else { return false };
    (1..=3).contains(&rest.split(':').count())
}

Prevention

When it happens

Trigger: Passing `rocksdb:/tmp/db:block_in_place:my_ns:extra`; a directory path or namespace containing colons; accidentally repeating a segment.

Common situations: Appending a segment copied from a scylladb/dual config string; absolute paths with stray colons; scripts concatenating config pieces with ':' separators.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/1f9e2a6daeeda09a. Report an issue: GitHub.