JuliusBrussee/caveman · error · ValueError
must be an absolute http(s) URL
Error message
{name} must be an absolute http(s) URL What it means
`_normalized_service_url` parses the URL with `urlsplit`; if parsing raises (e.g. an invalid port like `:abc`) or the parsed result is not an http/https absolute URL with a hostname, it raises this ValueError. The library only accepts absolute `http://` or `https://` URLs for service endpoints.
Solutions
- Prefix the URL with `https://` (or `http://` for local dev) if the scheme is missing.
- Use a full absolute URL including scheme and host, e.g. `https://cave.example.com`.
- Check for a malformed port (`host:port` must be numeric) or remove invalid characters.
- Ensure the value is non-empty before constructing.
Example fix
// before cave = Cave(api_key=key, service_url="localhost:8080") // after cave = Cave(api_key=key, service_url="http://localhost:8080")
Defensive patterns
Strategy: validation
Validate before calling
from urllib.parse import urlsplit
def is_absolute_http_url(v: str) -> bool:
try:
p = urlsplit(v)
except ValueError:
return False
return p.scheme in ("http", "https") and bool(p.hostname) Try / catch
try:
cave = Cave(api_key=key, service_url=url)
except ValueError:
url = "https://" + url.lstrip("/")
cave = Cave(api_key=key, service_url=url) Prevention
- Store full absolute URLs in config, never bare hosts
- Include the scheme explicitly, even for localhost
- Validate config once at startup
When it happens
Trigger: Passing a relative path (`/api`), a bare host (`localhost:8080` without scheme), a non-http scheme (`ftp://`), a malformed port, or an empty string as the service URL when constructing the config object.
Common situations: Config default of `""` left unfilled, forgetting the `https://` scheme prefix, or using `ws://`/custom schemes against the SDK.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- invalid_endpoint
- must be an absolute http(s) URL without credentials
- must not contain a query or fragment
- must not contain surrounding whitespace
- artifact_id is required
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/6f00fc34e6a500ff.
Report an issue: GitHub.
Appendix: source
Thrown at packages/sdk/python/caveman_cloud/core.py:336
_POLICY_MAX_RESPONSE_BYTES = 1024 * 1024
def _env_workflow() -> str:
"""CAVE_WORKFLOW normalized to the gateway label rule, else the honest default."""
raw = (os.environ.get("CAVE_WORKFLOW") or "").lower()
if raw and len(raw) <= 96 and all(c in _WORKFLOW_CHARS for c in raw):
return raw
return "unlabeled-workflow"
def _normalized_service_url(value: str, name: str) -> str:
if value.strip() != value:
raise ValueError(f"{name} must not contain surrounding whitespace")
try:
parsed = urlsplit(value)
port = parsed.port
except (TypeError, ValueError) as error:
raise ValueError(f"{name} must be an absolute http(s) URL") from error
if (
parsed.scheme not in ("http", "https")
or not parsed.hostname
or parsed.username is not None
or parsed.password is not None
):
raise ValueError(f"{name} must be an absolute http(s) URL without credentials")
if parsed.query or parsed.fragment:
raise ValueError(f"{name} must not contain a query or fragment")
return value.rstrip("/")
@dataclass
class Cave:
api_key: str
base_url: str
agent: str
# CAVE_WORKFLOW lets a wrapper (`cave wrap --workflow x`) label every requestView on GitHub (pinned to 3ee70a1026)