JuliusBrussee/caveman · error · ValueError

Bind runtime with…

Error message

Bind runtime {key!r} with caveman_middleware.autogen.component_runtimes before loading

What it means

The AutoGen adapter resolves its MiddlewareRuntime lazily from a ContextVar registry (caveman_middleware.autogen.component_runtimes) keyed by string. When AutoGen deserializes a component from config (component_config), the adapter's _from_config calls _runtime(key), and if no runtime was bound under that key before loading, this ValueError is raised. It exists so runtime objects (which are not serializable) can be re-attached after config-based component loading.

Solutions

  1. Wrap the load call in `with caveman_middleware.autogen.component_runtimes({'<key>': runtime}):` using the exact key from the component config
  2. Print/inspect the component config to find the expected key and make the bind key match exactly (it is case-sensitive)
  3. Perform the bind inside the same coroutine/task that performs the load so the ContextVar is visible (contextvars do not cross task boundaries automatically)
  4. Re-bind the runtime after process restart before calling load_component; config files alone cannot restore a runtime

Example fix

// before
client = ChatCompletionClient.load_component(cfg)  # ValueError: Bind runtime 'main' ...
// after
import caveman_middleware.autogen as cm_autogen
with cm_autogen.component_runtimes({'main': runtime}):
    client = ChatCompletionClient.load_component(cfg)
Defensive patterns

Strategy: try-catch

Validate before calling

from caveman_middleware.autogen import component_runtimes
key = cfg.get('component_type') and extract_runtime_key(cfg)  # your config's runtime key
assert key in _known_bound_keys, f'bind runtime {key!r} via component_runtimes before load'

Try / catch

try:
    with component_runtimes({'main': runtime}):
        client = ChatCompletionClient.load_component(cfg)
except ValueError as e:
    if str(e).startswith('Bind runtime'):
        logging.error('runtime key missing at load: %s', e)
    raise

Prevention

When it happens

Trigger: Loading an AutoGen component (e.g. via ChatCompletionClient.load_component(...) or Workbench.load_component) from a serialized config whose caveman runtime key was never registered via the component_runtimes context manager; a typo'd/mismatched key between bind and load; binding in a different task/async context so the ContextVar is not visible; deserializing in a fresh process (worker restart, CI, notebook) where only JSON config exists.

Common situations: AutoGen apps that serialize components to YAML/JSON for deployment; key changed after refactor but old serialized configs still reference it; binding done at module top-level in one file while load happens inside a different asyncio task where the context var did not propagate.

Related errors


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

Appendix: source

Thrown at packages/middleware/python/caveman_middleware/autogen.py:66

    Configurations store a reference key, never runtime credentials. Loading a
    key requires this explicit application-owned binding; the key grants no
    authority by itself. Nested contexts restore the previous bindings.
    """
    token = _component_runtimes.set({**_component_runtimes.get(), **runtimes})
    loaded = []
    resources = _loaded_components.set(loaded)
    try:
        yield loaded
    finally:
        _loaded_components.reset(resources)
        _component_runtimes.reset(token)


def _runtime(key):
    try:
        return _component_runtimes.get()[key]
    except KeyError:
        raise ValueError(f"Bind runtime {key!r} with caveman_middleware.autogen.component_runtimes before loading") from None


def _supported(runtime):
    return supports_framework(runtime, ("autogen-core", "0.7", "0.8"), ("autogen-agentchat", "0.7", "0.8"), ("autogen-ext", "0.7", "0.8"))


def _version_supported():
    return matches_framework(("autogen-core", "0.7", "0.8"), ("autogen-agentchat", "0.7", "0.8"), ("autogen-ext", "0.7", "0.8"))


def _check(runtime, scope):
    if not isinstance(scope, Scope):
        raise TypeError("AutoGen requires a stable Caveman Scope for each agent or model context")
    return runtime.as_async() if isinstance(runtime, MiddlewareRuntime) else runtime


def _schema():
    parameters = copy.deepcopy(RECOVERY_SCHEMA)

View on GitHub (pinned to 3ee70a1026)