xai-org/grok-build · error

Invalid GCS URL scheme: expected 'gs', got '{}'

Error message

Invalid GCS URL scheme: expected 'gs', got '{}'

What it means

upload_bytes (used by upload_bytes_signed) parses the configured bucket_url as a URL and requires the scheme to be 'gs' for direct (non-HTTP) GCS access. If the scheme is anything else (https, s3, or a typo), it bails with this message naming the offending scheme. This guards against misconfigured storage endpoints being handed to the GCS-specific code path.

Source

Thrown at crates/codegen/xai-file-utils/src/gcs.rs:116

/// Uploads bytes to cloud storage at the specified path.
/// Returns the full storage URL on success.
/// Dispatches to direct, proxy, or S3 backend based on config.
pub async fn upload_bytes<C: StorageConfig>(
    config: &C,
    object_path: &str,
    content: &[u8],
    content_type: &str,
) -> anyhow::Result<String> {
    match config.upload_method() {
        UploadMethod::Direct {
            service_account_key,
        } => {
            // Parse the bucket URL to extract bucket name (required for direct mode)
            let url = url::Url::parse(config.bucket_url())
                .with_context(|| format!("Invalid GCS URL: {}", config.bucket_url()))?;

            if url.scheme() != "gs" {
                anyhow::bail!(
                    "Invalid GCS URL scheme: expected 'gs', got '{}'",
                    url.scheme()
                );
            }

            let bucket = url
                .host_str()
                .context("GCS URL must have a bucket name")?
                .to_string();

            upload_bytes_direct(
                &bucket,
                object_path,
                content,
                content_type,
                service_account_key.as_deref(),
            )
            .await

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Set bucket_url to a proper gs:// URL, e.g. gs://my-bucket (optionally with object prefix).
  2. Check the env var/config source feeding bucket_url for typos (gcs://, GS://) — the scheme is compared case-sensitively after URL parsing.
  3. If you have an HTTPS endpoint intentionally (emulator/proxy), use the non-direct upload mode instead of the direct gs:// path.
  4. Validate the URL at startup (parse and assert scheme == "gs") so failures surface in config checks, not mid-upload.

Example fix

// before
let config = GcsConfig { bucket_url: "https://storage.googleapis.com/my-bucket".into(), .. };
upload_bytes(&config, key, data).await?;
// after
let config = GcsConfig { bucket_url: "gs://my-bucket".into(), .. };
upload_bytes(&config, key, data).await?;
Defensive patterns

Strategy: validation

Validate before calling

fn validate_gcs_bucket_url(bucket_url: &str) -> Result<(), String> {
    let url = url::Url::parse(bucket_url).map_err(|e| format!("bad URL: {e}"))?;
    if url.scheme() != "gs" {
        return Err(format!("scheme must be 'gs', got '{}' in {bucket_url}", url.scheme()));
    }
    if url.host_str().unwrap_or_default().is_empty() {
        return Err("missing bucket name".into());
    }
    Ok(())
}
validate_gcs_bucket_url(config.bucket_url())?; // run at startup, not mid-upload

Try / catch

match upload_bytes(&config, key, data).await {
    Err(e) if e.to_string().contains("Invalid GCS URL scheme") => {
        return Err(anyhow::anyhow!(
            "config error: bucket_url={} must be a gs:// URL",
            config.bucket_url()
        ));
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling upload_bytes/upload_bytes_signed with a config whose bucket_url() is set to an https:// URL, an s3:// URL, a bare hostname, or a misspelled scheme (gcs://, GS://).

Common situations: Copy-pasting a signed HTTPS console URL into bucket_url config; reusing an S3-style config struct for GCS; environment-variable substitution producing an empty or wrong-prefixed URL; docs examples mixing cloud providers.

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/bc1986fa67f35603. Report an issue: GitHub.