Tencent/WeKnora · error

create sandbox binding: %w

Error message

create sandbox binding: %w

What it means

This error wraps a failure from bindings.Create when persisting the binding for a newly created sandbox. The sandbox was created successfully, but without a durable binding the session could not be re-resolved later, so the lifecycle cleans up the fresh sandbox (cleanupCreated) and returns 'create sandbox binding: %w' joined with any cleanup error via errors.Join.

Source

Thrown at internal/sandbox/session_lifecycle.go:387

		return nil, errors.Join(
			fmt.Errorf("recheck owning session: %w", checkErr),
			l.cleanupCreated(ctx, handle),
		)
	}
	if !exists {
		return nil, errors.Join(ErrSandboxSessionDeleted, l.cleanupCreated(ctx, handle))
	}

	binding := l.newBinding(
		key,
		handle.ID(),
		request.TemplateID,
		l.now().UTC(),
	)
	created, bindErr := l.bindings.Create(ctx, key, binding)
	if bindErr != nil {
		return nil, errors.Join(
			fmt.Errorf("create sandbox binding: %w", bindErr),
			l.cleanupCreated(ctx, handle),
		)
	}
	if created {
		return handle, nil
	}

	winner, winnerErr := l.readBinding(ctx, key)
	if winnerErr != nil {
		// The authoritative winner is unknown, so deleting this sandbox could
		// destroy the resource another coordinator just bound.
		return nil, fmt.Errorf("read winning sandbox binding: %w", winnerErr)
	}
	if winner != nil &&
		winner.Provider == l.client.Provider() &&
		winner.SandboxID == handle.ID() {
		return handle, nil
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Inspect the wrapped (joined) error for binding-store detail; note the created sandbox is cleaned up automatically so retrying is safe
  2. Retry the resolve operation — a fresh sandbox will be created and bound
  3. Check for concurrent resolvers of the same session key and add client-side locking/idempotency if your store lacks it
  4. Verify write permissions and record size limits on the binding backend

Example fix

// before
// two goroutines resolve the same key concurrently
// after
cmu.Lock() // serialize resolution per session key in the host process
handle, err := session.Resolve(ctx, key)
mu.Unlock()
Defensive patterns

Strategy: retry

Validate before calling

// check binding-store writability before creating sandboxes
if err := bindings.HealthCheck(ctx); err != nil {
    return fmt.Errorf("skip create; binding store down: %w", err)
}

Try / catch

handle, err := session.Resolve(ctx, key)
if err != nil && errors.Is(err, context.Canceled) {
    // joined cleanup error: inspect both halves
    return err
} else if err != nil && strings.Contains(err.Error(), "create sandbox binding:") {
    // created sandbox was cleaned up; safe to retry
    err = retryWithBackoff(ctx, 3, func() error { handle, err = session.Resolve(ctx, key); return err })
}

Prevention

When it happens

Trigger: l.bindings.Create(ctx, key, binding) returns an error during createAndBind, immediately after a successful client.Create and session-existence recheck — binding store unavailability, write conflicts with a concurrent resolver that won the race, permission errors, or invalid binding record fields.

Common situations: Two processes resolving the same session concurrently (one binds first; store rejects or errors for the other); binding-store outage; schema migration in progress; quota/size limits on the binding record (e.g. large metadata); revoked write permissions.

Related errors


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