{"record":{"id":"17009efa0e3d655c","repo":"JuliusBrussee/caveman","slug":"invalid-endpoint-17009e","errorCode":"invalid_endpoint","errorMessage":"invalid_endpoint","messagePattern":"invalid_endpoint","errorType":"error_code","errorClass":"MiddlewareError","httpStatus":null,"severity":"error","filePath":"packages/sdk/python/caveman_cloud/middleware/runtime.py","lineNumber":67,"sourceCode":"    return PreflightReport(1, \"disabled\" if reason == \"disabled\" else \"ready\" if reason in (\"ready\", \"record_only\") else \"unavailable\",\n                           reason, mode, caps.get(\"mode\"), caps.get(\"runtime_build\") if validate.token(caps.get(\"runtime_build\")) else None,\n                           caps.get(\"policy_revision\"), caps.get(\"persistent\"), caps.get(\"recovery\"), PREFLIGHT_ACTIONS[reason])\n\n\ndef _json(value: Any) -> str:\n    return json.dumps(value, ensure_ascii=False, separators=(\",\", \":\"), allow_nan=False)\n\n\nclass MiddlewareRuntime:\n    def __init__(self, *, endpoint: str = \"http://127.0.0.1:8787\", token: str | None = None,\n                 allow_remote_content: bool = False, mode: str = \"compress\", deadline_ms: int = 100,\n                 retrieve_deadline_ms: int = 5000,\n                 strict: bool = False, on_diagnostic: Callable[[dict], None] | None = None,\n                 on_report: Callable[[CallReport], None] | None = None):\n        url = urlsplit(endpoint)\n        local = url.hostname in (\"127.0.0.1\", \"::1\", \"localhost\")\n        if url.scheme not in (\"http\", \"https\") or not url.hostname or url.username or url.password or url.query or url.fragment or url.path not in (\"\", \"/\"):\n            raise MiddlewareError(\"invalid_endpoint\")\n        if not local and (not allow_remote_content or url.scheme != \"https\"):\n            raise MiddlewareError(\"remote_content_not_enabled\")\n        if type(deadline_ms) is not int or deadline_ms <= 0 or mode not in (\"off\", \"record\", \"compress\"):\n            raise MiddlewareError(\"invalid_configuration\")\n        # A model asking to see an original is waiting on a page of stored text,\n        # not on the optimizer in front of a provider call. Separate budget.\n        if type(retrieve_deadline_ms) is not int or retrieve_deadline_ms <= 0:\n            raise MiddlewareError(\"invalid_configuration\")\n        self.endpoint = f\"{url.scheme}://{url.netloc}\"\n        self.mode, self.deadline_ms, self.strict = mode, deadline_ms, strict\n        self.retrieve_deadline_ms = retrieve_deadline_ms\n        self._token, self._diagnostic = token, on_diagnostic\n        self._report_sink, self._last_report = on_report, None\n        self._url = url\n        self._connections: set[http.client.HTTPConnection] = set()\n        self._caps: dict | None = None\n        self._bindings: weakref.WeakKeyDictionary[RecoveryBinding, tuple] = weakref.WeakKeyDictionary()\n        self._lock = threading.RLock()","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/sdk/python/caveman_cloud/middleware/runtime.py#L49-L85","documentation":"The middleware runtime constructor validates the endpoint URL strictly: scheme must be http/https, hostname present, no credentials/query/fragment, and path must be empty or \"/\". Any other URL shape raises MiddlewareError(\"invalid_endpoint\") at construction time, before any network I/O.","triggerScenarios":"Passing endpoints like \"caveman://...\", \"http://host/base/path\", \"https://user:pass@host\", URLs with ?query or #fragment, or an empty/unparsable endpoint string.","commonSituations":"Appending a base path (e.g. \"http://localhost:8080/api/v1\") because other HTTP clients allow it; leaving a template placeholder unfilled; including credentials in the URL out of habit.","solutions":["Pass a bare origin: scheme + host + optional port only, e.g. \"http://127.0.0.1:8080\" or \"https://proxy.example.com\"","Move any path/query into request configuration elsewhere — the runtime only accepts \"\" or \"/\" as path","Remove userinfo (user:pass@) from the URL; supply credentials via headers/tokens instead","Pre-validate with urllib.parse.urlsplit before constructing"],"exampleFix":"// before\nRuntime(endpoint=\"http://localhost:8080/api/v1?key=abc\")\n// after\nRuntime(endpoint=\"http://localhost:8080\")  # bare origin; no path, query, or credentials","handlingStrategy":"validation","validationCode":"from urllib.parse import urlsplit\ndef valid_endpoint(endpoint: str) -> bool:\n    u = urlsplit(endpoint)\n    return (u.scheme in ('http', 'https') and bool(u.hostname)\n            and not u.username and not u.password\n            and not u.query and not u.fragment\n            and u.path in ('', '/'))","typeGuard":"def is_bare_origin(endpoint: object) -> bool:\n    if not isinstance(endpoint, str):\n        return False\n    from urllib.parse import urlsplit\n    u = urlsplit(endpoint)\n    return (u.scheme in ('http', 'https') and bool(u.hostname)\n            and not (u.username or u.password or u.query or u.fragment)\n            and u.path in ('', '/'))","tryCatchPattern":"try:\n    runtime = Runtime(endpoint=ep)\nexcept MiddlewareError as e:\n    if str(e) == 'invalid_endpoint':\n        raise ConfigError(f'endpoint must be a bare http(s) origin, got {ep!r}') from e\n    raise","preventionTips":["Pass only scheme://host[:port] — no path, query, fragment, or credentials","Validate endpoints with urlsplit in your config loader before constructing the runtime","Keep path/version prefixes in the application layer, not the endpoint","Strip credentials from URLs and use token/header configuration instead"],"tags":["python","url","validation","middleware"],"backgroundTag":"invalid-url-format","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}