Tencent/WeKnora · error
release stale sandbox binding: %w
Error message
release stale sandbox binding: %w
What it means
When a binding is stale (its sandbox boots an image the config has since replaced) and a rebuild is permitted at this turn boundary, resolveLocked destroys the old sandbox via destroyBindingLocked before the recovery pass re-creates/adopts one. This error wraps a failure of that destroy (provider Destroy API error, binding store error, or context cancellation). Destroying before rebuilding is required — a surviving stale sandbox would simply be re-adopted — so the lifecycle refuses to continue on failure.
Source
Thrown at internal/sandbox/session_lifecycle.go:192
if !deleted {
return nil, errors.New("mismatched provider binding changed during replacement")
}
binding = nil
}
// A stale binding is one whose sandbox boots an image the config has since
// replaced. Rebuild waits for a turn boundary: the first resolve of a new
// chat turn may destroy and recreate, later resolves of that same turn
// keep the sandbox so /workspace scratch and in-flight execs survive an
// install that landed mid-turn. A resolve with no turn lease (no AgentQA
// in flight) still rebuilds immediately.
//
// Destroying before rebuilding is not optional: the recovery pass below
// adopts any live sandbox carrying this session's metadata, so a surviving
// one would simply be picked up again.
if binding != nil && binding.StaleAt != nil && l.shouldRebuildStaleBinding(ctx, key) {
if err := l.destroyBindingLocked(ctx, key, *binding); err != nil {
return nil, fmt.Errorf("release stale sandbox binding: %w", err)
}
binding = nil
}
// First resolve of a turn spends rebuildOnce even when nothing was stale,
// so a later install in the same turn cannot tear the sandbox down.
l.consumeTurnRebuild(ctx, key)
if binding != nil {
handle, replace, err := l.connectBinding(ctx, *binding)
if err != nil {
return nil, err
}
if !replace {
return handle, nil
}
deleted, err := l.bindings.DeleteIfMatch(
ctx,
key,View on GitHub (pinned to 988cbb0330)
Solutions
- Retry Resolve with backoff — the rebuild will be re-attempted at the next eligible resolve.
- Check the provider destroy error in the %w chain; verify the cleanupTimeout is generous enough for the provider's delete latency.
- If the provider API is degraded, wait for recovery; the old stale sandbox may keep running (and billing) until destroy succeeds — check the provider console for orphans.
- Avoid cancelling requests during turn-start resolves so rebuilds complete.
Example fix
// before
cleanupTimeout := 5 * time.Second // too short for provider deletes
// after
cleanupTimeout := 60 * time.Second // tolerate provider delete latency during stale rebuild
// plus retry on resolve:
for i := 0; i < 3; i++ {
handle, err = lifecycle.Resolve(ctx, key)
if err == nil || errors.Is(err, sandbox.ErrSandboxSessionDeleted) { break }
time.Sleep(time.Duration(1<<i) * time.Second)
} Defensive patterns
Strategy: retry
Validate before calling
open, canRebuild, err := store.TurnState(ctx, key)
if err == nil && !canRebuild {
// stale rebuild will be deferred to next turn boundary; no destroy imminent
} Try / catch
handle, err := lifecycle.Resolve(ctx, key)
if err != nil && strings.Contains(err.Error(), "release stale sandbox binding") {
// provider destroy failed during rebuild; retry next turn boundary
time.Sleep(backoff)
handle, err = lifecycle.Resolve(ctx, key)
} Prevention
- Rotate sandbox templates/images outside peak traffic so stale rebuilds have API headroom.
- Set cleanupTimeout above the provider's p99 delete latency.
- Don't cancel turn-start requests mid-resolve; use detached cleanup contexts.
- Watch for orphaned stale sandboxes in the provider console after rebuild failures.
When it happens
Trigger: A sandbox config/template change marked existing bindings stale; the first resolve of a new turn (or a resolve with no turn lease) triggers shouldRebuildStaleBinding; the destroyBindingLocked call fails because the provider API errors or the context is cancelled mid-destroy.
Common situations: Rotating the sandbox image/template while sessions are live; provider API outage or rate limiting exactly at rebuild time; cleanupTimeout too short so the provider destroy times out; user cancels the request mid-rebuild.
Related errors
- sandbox: config is missing required fields
- cube remote client config is required
- cube api: create sandbox: empty sandboxID
- sandbox: docker backend is disabled; enable it in System Set
- sandbox: docker client requires a config
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/901406a10c2cf65f.
Report an issue: GitHub.