github/spec-kit · error · BundlerError
A catalog url is required.
Error message
A catalog url is required.
What it means
Raised by `add_source()` when the `url` argument is empty after stripping. Adding a catalog source requires a URL pointing at the catalog (http(s)://, file://, builtin://, or a local path); a blank one cannot proceed.
Source
Thrown at src/specify_cli/bundler/commands_impl/catalog_config.py:145
host = parsed.hostname or ""
path_stem = Path(parsed.path).stem if parsed.path else ""
parts = [p for p in (_slug(host), _slug(path_stem)) if p]
return "-".join(parts) or "catalog"
stem = Path(parsed.path or url).stem
return _slug(stem) or "catalog"
def add_source(
project_root: Path,
url: str,
*,
policy: str,
priority: int,
source_id: str | None = None,
) -> CatalogSource:
url = url.strip()
if not url:
raise BundlerError("A catalog url is required.")
try:
parsed = urlparse(url)
# Read .hostname inside the try: a bracketed-but-invalid IPv6 authority
# (e.g. "https://[not-an-ip]/c.json") parses cleanly under urlparse() on
# Python < 3.14 but raises ValueError lazily on the first .hostname access
# (the raise moved eager into urlparse() only in 3.14). Reading it here
# keeps that ValueError inside the guard instead of leaking a raw
# traceback past the CLI's `except BundlerError`. Reuse the value below.
hostname = parsed.hostname
# Accessing ``port`` performs urllib's syntax/range validation.
_ = parsed.port
except ValueError as exc:
raise BundlerError(f"Invalid catalog url: '{url}'.") from exc
if not (parsed.scheme or parsed.path):
raise BundlerError(f"Invalid catalog url: '{url}'.")
# Reject unsupported URL schemes (e.g. ssh://, ftp://) up front so they are
# never silently canonicalized as local filesystem paths. Local paths that
# merely contain a ':' but no '://' (e.g. Windows drives) are still allowed.View on GitHub (pinned to bf88c9f9a8)
Solutions
- Supply a non-empty catalog URL (https://…, file://…, builtin://…, or a local path)
- Guard the caller: fail early if the URL variable is empty before invoking add
- Use shell defaults like `${CATALOG_URL:?CATALOG_URL required}`
Example fix
# before
specify bundle catalog add "$MAYBE_UNSET_URL" --policy auto
# after
specify bundle catalog add "${CATALOG_URL:?CATALOG_URL required}" --policy auto Defensive patterns
Strategy: validation
Validate before calling
url = (url or "").strip()
if not url:
raise SystemExit("catalog URL is required (https://…, file://…, builtin://…, or local path)") Type guard
def is_nonempty_url(url: object) -> bool:
return isinstance(url, str) and bool(url.strip()) Try / catch
try:
add_source(project_root, url, policy=policy, priority=50)
except BundlerError as exc:
if "A catalog url is required" in str(exc):
# re-prompt for the URL; do not silently pass ""
raise
raise Prevention
- Use shell guards like ${CATALOG_URL:?required} so empty variables abort early
- Fail fast on empty inputs in wrappers instead of forwarding them
When it happens
Trigger: Calling the catalog-add API with `url=""`, `url=" "`, or a variable that expanded to nothing.
Common situations: Shell script passing an unset `$CATALOG_URL` without `set -u`/defaults; CLI invocation missing the positional URL argument in a wrapper; CI variable name typo yielding an empty string.
Related errors
- Malformed catalog config at {path}: expected a mapping at th
- Malformed catalog config at {path}: 'catalogs' must be a lis
- Malformed catalog config at {path}: each catalog entry must
- Invalid catalog url: '{url}'.
- Unsupported catalog url scheme '{parsed.scheme}://' in '{url
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/ca8d14bab4c24229.
Report an issue: GitHub.