langchain-ai/deepagents · error · RuntimeError

Blueprint '{blueprint_name}' exists but its last build faile

Error message

Blueprint '{blueprint_name}' exists but its last build failed. Delete it and retry, or fix the Dockerfile. | Blueprint '{blueprint_name}' exists but is still building (state '{status}'). Wait for it to finish, or delete it to rebuild.

What it means

Raised by `_ensure_blueprint` when a blueprint with the requested name exists in Runloop but its status is not `build_complete`. A `failed` status is terminal so the message advises deleting it or fixing the Dockerfile; any other non-complete status (`queued`, `provisioning`, `building`) means the build is still in flight and the caller should wait or delete to rebuild. The function intentionally refuses to create a duplicate or block indefinitely on a same-name blueprint.

Source

Thrown at libs/partners/runloop/langchain_runloop/provider.py:111

        try:
            page = client.blueprints.list(**list_kwargs)
        except Exception as e:
            msg = f"Failed to list blueprints: {e}"
            raise RuntimeError(msg) from e

        for blueprint in page.blueprints:
            if blueprint.name != blueprint_name:
                continue
            if blueprint.status == "build_complete":
                return
            non_ready_status = blueprint.status

        if not page.has_more or not page.blueprints:
            break
        starting_after = page.blueprints[-1].id

    if non_ready_status is not None:
        raise RuntimeError(_not_ready_message(blueprint_name, non_ready_status))

    try:
        client.blueprints.create_and_await_build_complete(
            name=blueprint_name,
            dockerfile=dockerfile,
        )
    except Exception as create_err:
        msg = f"Failed to build blueprint '{blueprint_name}': {create_err}"
        raise RuntimeError(msg) from create_err


class RunloopProvider:
    """Create or attach Runloop devboxes, optionally from named blueprints."""

    def __init__(
        self,
        *,
        api_key: str,

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Check the blueprint status in the Runloop dashboard; if still building, wait and retry later.
  2. If status is `failed`, delete the blueprint (API or dashboard) and retry so `_ensure_blueprint` rebuilds it.
  3. Fix the Dockerfile (e.g. pass `blueprint_dockerfile=` with a working Dockerfile) before deleting and rebuilding.
  4. Alternatively boot by blueprint ID instead: set `RUNLOOP_SANDBOX_BLUEPRINT_ID`, which skips the name-based ensure path entirely.
  5. Or unset `snapshot`/`RUNLOOP_SANDBOX_BLUEPRINT_NAME` to create a plain empty devbox.

Example fix

// before
sandbox = provider.get_or_create(snapshot="my-bp")  # RuntimeError: still building

// after
import time
try:
    sandbox = provider.get_or_create(snapshot="my-bp")
except RuntimeError as e:
    if "still building" in str(e):
        time.sleep(60)
        sandbox = provider.get_or_create(snapshot="my-bp")
    elif "last build failed" in str(e):
        client.blueprints.delete(name="my-bp")  # then retry
        sandbox = provider.get_or_create(snapshot="my-bp")
Defensive patterns

Strategy: retry

Validate before calling

import time

def wait_until_blueprint_ready(client, name, timeout_s=600):
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        status = get_blueprint_status(client, name)  # paginated list by name
        if status == "build_complete":
            return True
        if status == "failed":
            return False
        time.sleep(10)
    return False

Type guard

def is_blueprint_ready(status: str | None) -> bool:
    return status == "build_complete"

Try / catch

try:
    sandbox = provider.get_or_create(snapshot="my-bp")
except RuntimeError as e:
    if "last build failed" in str(e):
        delete_blueprint("my-bp")  # then rebuild once
        sandbox = provider.get_or_create(snapshot="my-bp")
    elif "still building" in str(e):
        time.sleep(60)  # poll until ready, then retry
    else:
        raise

Prevention

When it happens

Trigger: Calling `RunloopProvider.get_or_create` (directly or via `snapshot=` or `RUNLOOP_SANDBOX_BLUEPRINT_NAME`) when the named blueprint exists with status `failed`, `queued`, `provisioning`, or `building` after `_ensure_blueprint` paginates through `client.blueprints.list(name=..., limit=100)` without finding a `build_complete` match.

Common situations: A previous build of the blueprint failed due to a bad Dockerfile; a CI job or teammate kicked off a rebuild that is still running; a stale failed blueprint from an earlier experiment shares the name.

Related errors


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/df55e8222f2a47dc. Report an issue: GitHub.