Hmbown/CodeWhale · error
outbound origin must be http or https
Error message
outbound origin must be http or https
What it means
validate_outbound_origin only accepts http/https schemes; any other scheme (file:, ftp:, ws:, etc.) is rejected before any request is built. This closes the SSRF door on non-HTTP transports for credential-bearing calls.
Solutions
- Change the configured origin to start with https:// (http is only useful for loopback in debug builds).
- Strip custom scheme prefixes (ws://, file://) from the config value before validation.
- Verify which env/config field you set — you may have populated the wrong variable.
Example fix
// before export DAYTONA_API_URL=ftp://api.example.com // after export DAYTONA_API_URL=https://api.example.com
Defensive patterns
Strategy: validation
Validate before calling
if !raw.trim().starts_with("https://") { return Err("origin must start with https://"); } Try / catch
if let Err(e) = validate_outbound_origin(raw) {
if e.to_string().contains("http or https") {
eprintln!("fix the scheme of the configured origin: {raw}");
}
} Prevention
- Always write origins with explicit https:// in config.
- Add a config-load-time scheme check.
- Avoid copy-pasting non-http URL schemes into endpoint settings.
When it happens
Trigger: Configuring an endpoint like file:///etc/passwd, ftp://host/x, or ws://... as the outbound origin (DAYTONA_API_URL, remote endpoint, or sandbox toolbox_url).
Common situations: Copy-pasting a websocket or internal file URL into a remote-endpoint setting; typo'd scheme like htp:// still parses via other schemes handling.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- outbound origin is empty or oversized
- outbound origin must be a public service host
- agent profile provider cannot be empty
- agent profile provider must be a simple provider id
- api_key cannot be empty string
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/6ce2326dc7115011.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/cloud_dispatch.rs:1264
///
/// Rules:
/// - `https` only for public hosts.
/// - explicit loopback hosts (`localhost`, `127.0.0.1`, `::1`) are allowed
/// only in debug builds, as the escape hatch for local smoke tests against
/// a self-hosted sandbox service; release builds reject them outright.
/// - the host must not be a private / link-local / reserved / multicast
/// address or a `.local` / `.internal` name, and no userinfo may ride
/// along.
///
/// DNS-resolved rebinding is out of scope and documented as such.
pub fn validate_outbound_origin(raw: &str) -> Result<reqwest::Url> {
let trimmed = raw.trim();
if trimmed.is_empty() || trimmed.len() > MAX_REMOTE_BYTES {
bail!("outbound origin is empty or oversized");
}
let url = reqwest::Url::parse(trimmed).context("outbound origin is not a valid URL")?;
if !matches!(url.scheme(), "http" | "https") {
bail!("outbound origin must be http or https");
}
if !url.username().is_empty() || url.password().is_some() {
bail!("outbound origin must not embed credentials");
}
let host = url
.host_str()
.context("outbound origin has no host")?
.trim_end_matches('.')
.to_ascii_lowercase();
// `Url::host_str` keeps IPv6 brackets; strip them for the checks below.
let host = host
.strip_prefix('[')
.and_then(|inner| inner.strip_suffix(']'))
.map(str::to_string)
.unwrap_or(host);
let loopback_name = host == "localhost" || host == "127.0.0.1" || host == "::1";
if loopback_name {
if cfg!(debug_assertions) {View on GitHub (pinned to 73e0f67d83)