JuliusBrussee/caveman · warning · MiddlewareError

off

off

Error message

off

What it means

ready() raises MiddlewareError("off") when the runtime was constructed with mode="off". In off mode the middleware is intentionally disabled: it performs no HTTP capability check and never reports ready. This is a configuration signal, not a network failure.

Solutions

  1. Check runtime.mode before calling ready(); skip readiness checks when mode == "off".
  2. If the middleware should be active, reconfigure the runtime with mode set to "on"/"strict" (not "off").
  3. Fix the environment/config source (env var, config file) that forced mode="off".

Example fix

// before
report = runtime.ready()
// after
if runtime.mode != "off":
    report = runtime.ready()
else:
    report = None  # middleware intentionally disabled
Defensive patterns

Strategy: validation

Validate before calling

def ready_safe(rt):
    return rt.ready() if rt.mode != "off" else None

Type guard

def middleware_enabled(rt) -> bool:
    return getattr(rt, "mode", "off") != "off"

Try / catch

try:
    caps = rt.ready()
except MiddlewareError as e:
    if str(e) == "off":
        caps = None  # middleware intentionally disabled
    else:
        raise

Prevention

When it happens

Trigger: Calling ready() (directly or via preflight()) on a runtime whose mode is "off".

Common situations: Middleware disabled via env/config for local dev or CI, then code that unconditionally calls ready(); stale config where the service was expected to be enabled.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/dad65fda0e227e97. Report an issue: GitHub.

Appendix: source

Thrown at packages/sdk/python/caveman_cloud/middleware/runtime.py:106

        self._failures = 0
        self._open_until = 0.0
        self._receipt_pool: ThreadPoolExecutor | None = None
        self._receipt_slots = threading.BoundedSemaphore(16)
        self._async_view = None

    def as_async(self):
        """Cached bounded async view; close() releases its owned worker pool."""
        from .async_runtime import AsyncMiddlewareRuntime
        with self._lock:
            if self._closed:
                raise MiddlewareError("closed")
            if self._async_view is None or self._async_view._closed:
                self._async_view = AsyncMiddlewareRuntime.from_sync(self)
            return self._async_view

    def ready(self) -> dict:
        if self.mode == "off":
            raise MiddlewareError("off")
        value = validate.capabilities(self._http("capabilities", None, self.deadline_ms / 1000))
        with self._lock:
            if self._closed:
                raise MiddlewareError("closed")
            self._caps = value
        return copy.deepcopy(value)

    def preflight(self) -> PreflightReport:
        """Nonthrowing discovery, even in strict mode; sends no candidate content."""
        if self.mode == "off":
            return _preflight_report(self.mode, "disabled")
        try:
            caps = self.ready()
            reason = ("record_only" if self.mode == "record" or caps["mode"] == "record"
                      else "recovery_unavailable" if not caps["persistent"] or not caps["recovery"] else "ready")
            return _preflight_report(self.mode, reason, caps)
        except Exception as error:
            with self._lock:

View on GitHub (pinned to 3ee70a1026)