Tencent/WeKnora · error

sandbox: list workspace %d config %q sandboxes: %w

Error message

sandbox: list workspace %d config %q sandboxes: %w

What it means

The reaper lists sandboxes matching the tenant/config filter via deps.Client.List; when the underlying store call fails, the error is wrapped with the workspace ID and normalized config ID so the failed scope is identifiable. This is a wrapped storage/backend error, not raised by the sandbox package logic itself.

Source

Thrown at internal/sandbox/orphan_reaper.go:69

	Grace time.Duration

	Now func() time.Time
}

// ReapOrphanSandboxes deletes unbound sandboxes for one tenant and reports how
// many were removed.
func ReapOrphanSandboxes(ctx context.Context, deps OrphanReaperDeps) (int, error) {
	if deps.Client == nil {
		return 0, fmt.Errorf("sandbox: orphan reaper requires a client")
	}
	now := deps.Now
	if now == nil {
		now = time.Now
	}

	summaries, err := deps.Client.List(ctx, configSandboxFilter(deps.TenantID, deps.ConfigID))
	if err != nil {
		return 0, fmt.Errorf(
			"sandbox: list workspace %d config %q sandboxes: %w",
			deps.TenantID, NormalizeConfigID(deps.ConfigID), err)
	}

	cutoff := now().Add(-deps.Grace)
	deleted := 0
	for _, summary := range summaries {
		if _, bound := deps.BoundIDs[summary.ID]; bound {
			continue
		}
		if deps.Grace > 0 && !summary.StartedAt.IsZero() && summary.StartedAt.After(cutoff) {
			continue
		}
		if err := deps.Client.Delete(ctx, summary.ID); err != nil {
			// Keep going: one undeletable sandbox must not abort the sweep.
			continue
		}
		deleted++

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Inspect the wrapped cause (%w) for the actual transport/auth failure and fix connectivity or credentials
  2. Retry the reap with backoff, since List failures are often transient
  3. Verify TenantID/ConfigID passed to the reaper match an existing workspace config
  4. Log the wrapped error with the workspace/config scope before alerting

Example fix

// before
_, err := sandbox.ReapOrphanSandboxes(ctx, deps) // err surfaces opaque store failure
// after
n, err := sandbox.ReapOrphanSandboxes(ctx, deps)
if err != nil {
    var nerr net.Error
    if errors.As(err, &nerr) { scheduleRetry(ctx, deps); return }
    log.Fatalf("reap failed for workspace %d: %v", deps.TenantID, err)
}
Defensive patterns

Strategy: retry

Validate before calling

if err := client.Ping(ctx); err != nil {
    return fmt.Errorf("sandbox store unreachable: %w", err)
}

Try / catch

n, err := sandbox.ReapOrphanSandboxes(ctx, deps)
if err != nil {
    var nerr net.Error
    if errors.As(err, &nerr) { return scheduleRetry(deps) }
    return err
}

Prevention

When it happens

Trigger: ReapOrphanSandboxes invoked with a Client whose List call returns an error — e.g. Redis down, network timeout, auth rejected, or malformed filter arguments like an invalid config ID.

Common situations: Store outage during a scheduled reap; wrong Redis address or credentials in the reaper's environment; deleted config whose ID no longer resolves server-side; transient network partitions in CI.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/ec7e89699a1af123. Report an issue: GitHub.