risingwavelabs/risingwave · error · anyhow::Error

Invalid header format

Error message

Invalid header format: {}

What it means

The `headers()` parser splits `catalog.header` on ';' then each pair on '=' and requires both a key and a value. A segment that does not yield both (e.g. empty segment or no '=') bails with `Invalid header format` showing the offending pair.

Solutions

  1. Format each header as `key=value`, separated by ';': e.g. `catalog.header = 'X-Client=wave;Authorization=Bearer xyz'`.
  2. Remove trailing/leading semicolons and empty segments.
  3. Ensure every pair contains '='; omit headers you cannot supply a value for.

Example fix

// before
catalog.header = 'Authorization=Bearer abc;'
// after
catalog.header = 'Authorization=Bearer abc'
Defensive patterns

Strategy: validation

Validate before calling

function validateHeaderStr(h) {
  if (h === '') return;
  for (const pair of h.split(';')) {
    if (pair.length === 0 || !pair.includes('=')) {
      throw new Error(`Invalid header format: ${pair}`);
    }
  }
}

Type guard

const isValidHeaderStr = (h) => h.split(';').every(p => p.includes('='));

Try / catch

catch (e) { if (String(e).startsWith('Invalid header format')) { /* echo the bad pair and show key=value;key2=value2 syntax */ } else { throw e; } }

Prevention

When it happens

Trigger: `catalog.header` containing an empty segment (double ';' or trailing ';'), or a token without '=' such as 'Authorization' with no value.

Common situations: Trailing semicolons after the last header; pasting a single header line without 'key=value'; whitespace-only segments.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/dd7799bb06eb9196. Report an issue: GitHub.

Appendix: source

Thrown at src/connector/src/connector_common/iceberg/mod.rs:586

        let user_agent = match Deployment::current() {
            Deployment::Ci => "RisingWave(CI)".to_owned(),
            Deployment::Cloud => "RisingWave(Cloud)".to_owned(),
            Deployment::Other => "RisingWave(OSS)".to_owned(),
        };
        if self.vended_credentials() {
            headers.insert(
                "X-Iceberg-Access-Delegation".to_owned(),
                "vended-credentials".to_owned(),
            );
        }
        headers.insert("User-Agent".to_owned(), user_agent);
        if let Some(header) = &self.catalog_header {
            for pair in header.split(';') {
                let mut parts = pair.split('=');
                if let (Some(key), Some(value)) = (parts.next(), parts.next()) {
                    headers.insert(key.to_owned(), value.to_owned());
                } else {
                    bail!("Invalid header format: {}", pair);
                }
            }
        }
        Ok(headers)
    }

    pub fn enable_config_load(&self) -> bool {
        // If the env var is set to true, we disable the default config load. (Cloud environment)
        if env_var_is_true(DISABLE_DEFAULT_CREDENTIAL) {
            if matches!(self.enable_config_load, Some(true)) {
                tracing::warn!(
                    "`enable_config_load` can't be enabled in SaaS environment, the behavior might be unexpected"
                );
            }
            return false;
        }
        self.enable_config_load.unwrap_or(false)
    }

View on GitHub (pinned to 6469eb736d)