zeroclaw-labs/zeroclaw · error · anyhow::Error

Generated image URL must be a non-empty URL without whitespa

Error message

Generated image URL must be a non-empty URL without whitespace

What it means

parse_public_https_url is the first gate on the image URL that the fal.ai image-generation tool extracts from the provider response. After trimming, the URL must be non-empty and contain no whitespace characters; anything else is rejected before parsing. In practice this error means the field pulled out of the fal.ai JSON was empty, truncated, or contained embedded spaces/newlines, so the downstream image download never starts.

Source

Thrown at crates/zeroclaw-tools/src/image_gen.rs:27

use zeroclaw_api::tool::{Tool, ToolOutput, ToolResult, with_ephemeral_workspace_warning};
use zeroclaw_config::policy::SecurityPolicy;
use zeroclaw_config::policy::ToolOperation;

const FAL_RESPONSE_LIMIT_BYTES: usize = 1024 * 1024;
const FAL_ERROR_LIMIT_BYTES: usize = 16 * 1024;
const GENERATED_IMAGE_LIMIT_BYTES: usize = 20 * 1024 * 1024;
const MAX_IMAGE_REDIRECTS: usize = 10;

struct ValidatedImageTarget {
    url: reqwest::Url,
    host: String,
    resolved_addrs: Vec<SocketAddr>,
}

fn parse_public_https_url(raw_url: &str) -> anyhow::Result<(reqwest::Url, String, u16)> {
    let raw_url = raw_url.trim();
    if raw_url.is_empty() || raw_url.chars().any(char::is_whitespace) {
        anyhow::bail!("Generated image URL must be a non-empty URL without whitespace");
    }

    let mut url = reqwest::Url::parse(raw_url).context("Invalid generated image URL")?;
    if url.scheme() != "https" {
        anyhow::bail!("Generated image URL must use HTTPS");
    }
    if !url.username().is_empty() || url.password().is_some() {
        anyhow::bail!("Generated image URL userinfo is not allowed");
    }

    let request_host = url
        .host_str()
        .ok_or_else(|| anyhow::Error::msg("Generated image URL must include a host"))?;
    if request_host.ends_with('.') {
        anyhow::bail!("Generated image URL host must not end with a dot");
    }
    let host = domain_guard::normalize_domain(request_host)
        .ok_or_else(|| anyhow::Error::msg("Generated image URL host is invalid"))?;

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Log or inspect the raw (bounded) fal.ai response body and check which field actually carries the image URL for the model you selected.
  2. Update the extraction to the correct field (e.g. images[0].url vs output[0] vs image_url) for the current model version.
  3. Trim the URL and verify it is non-empty before passing it on; treat an empty URL from the provider as a provider-side failure and retry the generation.

Example fix

// before
let url = payload["url"].as_str().unwrap_or("");

// after
let url = payload["images"][0]["url"].as_str().map(str::trim).filter(|u| !u.is_empty() && !u.chars().any(char::is_whitespace)).ok_or_else(|| anyhow::anyhow!("model returned no image URL"))?;
Defensive patterns

Strategy: validation

Validate before calling

fn clean_image_url(raw: &str) -> Option<&str> {
    let t = raw.trim();
    (!t.is_empty() && !t.chars().any(char::is_whitespace)).then_some(t)
}

Type guard

fn is_non_empty_url(s: &str) -> bool {
    let t = s.trim();
    !t.is_empty() && !t.chars().any(char::is_whitespace)
}

Try / catch

match validate_image_target(&url, nat64).await {
    Err(e) if e.to_string().contains("must be a non-empty URL") => {
        // provider returned a broken field: log the raw fal payload and retry generation once
    }
    other => other,
}

Prevention

When it happens

Trigger: The fal.ai request succeeds but the extracted URL field is empty (wrong field name for the model, e.g. reading 'url' when the model returns 'image_url' or an output array), a truncated or wrapped URL containing a newline, or a response shape change after a model/app version bump.

Common situations: Switching fal.ai models or app revisions whose payload uses a different JSON shape, extracting the wrong key from the response JSON, an auth failure body being parsed as if it were a success payload, and copy-pasted test URLs containing stray whitespace.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/b70bc0a78e0b59a1. Report an issue: GitHub.