Tencent/WeKnora · critical

create sandbox binding: %w

Error message

create sandbox binding: %w

What it means

Returned by RedisSessionSandboxBindingStore.Create when the client.SetNX call itself fails — Redis is unreachable, the context is cancelled/timed out, the connection dropped, or the server returned an error (e.g. READONLY on a replica). The binding was NOT stored. Wrapped as 'create sandbox binding: %w'. A returned (false, nil) means the key already existed (no error).

Source

Thrown at internal/sandbox/session_binding_redis.go:151

}

// Create stores a validated current-schema binding with SET NX and no
// expiration.
func (s *RedisSessionSandboxBindingStore) Create(
	ctx context.Context,
	key SessionSandboxKey,
	binding SessionSandboxBinding,
) (bool, error) {
	if err := binding.Validate(key); err != nil {
		return false, err
	}
	raw, err := json.Marshal(binding)
	if err != nil {
		return false, fmt.Errorf("encode sandbox binding: %w", err)
	}
	created, err := s.client.SetNX(ctx, s.bindingKey(key), raw, 0).Result()
	if err != nil {
		return false, fmt.Errorf("create sandbox binding: %w", err)
	}
	return created, nil
}

// DeleteIfMatch atomically deletes only the expected provider and sandbox ID.
func (s *RedisSessionSandboxBindingStore) DeleteIfMatch(
	ctx context.Context,
	key SessionSandboxKey,
	provider RemoteProvider,
	sandboxID string,
) (bool, error) {
	if err := validateBindingMatch(key, provider, sandboxID); err != nil {
		return false, err
	}
	deleted, err := deleteBindingIfMatchScript.Run(
		ctx,
		s.client,
		[]string{s.bindingKey(key)},

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Check Redis connectivity: redis-cli -h <host> -p <port> ping from the app host and verify REDIS_* env vars
  2. Retry Create — the operation is idempotent thanks to SET NX semantics (returns created=false if already present)
  3. Check redis-server logs for READONLY/maxmemory/ACL errors and fix the server-side condition
  4. Increase the request context timeout and go-redis pool settings (PoolSize, dial/read/write timeouts) if errors correlate with load

Example fix

// before
created, err := store.Create(ctx, key, binding)
if err != nil { return err }
// after: bounded retry for transient Redis failures
var created bool
for attempt := 0; attempt < 3; attempt++ {
    created, err = store.Create(ctx, key, binding)
    if err == nil { break }
    select {
    case <-ctx.Done():
        return ctx.Err()
    case <-time.After(time.Duration(1<<attempt) * 100 * time.Millisecond):
    }
}
if err != nil { return fmt.Errorf("create binding after retries: %w", err) }
if !created { /* binding already exists — proceed or fail per business rule */ }
Defensive patterns

Strategy: retry

Validate before calling

// verify Redis is reachable before critical write paths
if err := rdb.Ping(ctx).Err(); err != nil {
    return fmt.Errorf("redis unavailable before create: %w", err)
}

Type guard

func isTransientRedisError(err error) bool {
    if err == nil { return false }
    return errors.Is(err, context.DeadlineExceeded) ||
        errors.Is(err, context.Canceled) == false &&
        (errors.Is(err, io.EOF) || errors.Is(err, syscall.ECONNRESET) ||
         strings.Contains(err.Error(), "connection refused") ||
         strings.Contains(err.Error(), "pool timeout"))
}

Try / catch

var created bool
var err error
for i := 0; i < 3; i++ {
    if created, err = store.Create(ctx, key, binding); err == nil { break }
    if !isTransientRedisError(err) { break }
    select {
    case <-ctx.Done(): return ctx.Err()
    case <-time.After(backoff(i)):
    }
}
if err != nil { return err }
if !created { log.Printf("binding already existed for %s", key.SessionID) }

Prevention

When it happens

Trigger: Calling Create(ctx, key, binding) when: Redis is down or restarting; network partition between app and Redis; ctx deadline exceeded while waiting for SetNX; writing to a read-only replica; Redis at maxmemory with no eviction policy; auth (ACL/password) misconfigured.

Common situations: Redis container restarted during a deploy; wrong REDIS_HOST/PORT or password in env; failover in progress on a sentinel/cluster setup; connection pool exhausted under load; ops applied 'replica-read-only yes' incorrectly to the primary.

Related errors


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