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
- Log or inspect the raw (bounded) fal.ai response body and check which field actually carries the image URL for the model you selected.
- Update the extraction to the correct field (e.g. images[0].url vs output[0] vs image_url) for the current model version.
- 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
- Pin fal.ai model/app revisions so response JSON shape changes do not silently break field extraction.
- Trim and sanity-check provider-supplied URLs before use; treat empty as a provider failure and retry.
- Log the (bounded) provider response on failure so wrong-field extraction is obvious.
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
- Generated image URL host must not end with a dot
- providers.models.{profile_name}.uri must use http/https
- URL must include a valid host
- Generated image URL must use HTTPS
- Generated image URL userinfo is not allowed
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/b70bc0a78e0b59a1.
Report an issue: GitHub.