{"record":{"id":"370abb49ede1cab2","repo":"Tencent/WeKnora","slug":"create-sandbox-binding-w","errorCode":null,"errorMessage":"create sandbox binding: %w","messagePattern":"create sandbox binding: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/sandbox/session_binding_redis.go","lineNumber":151,"sourceCode":"}\n\n// Create stores a validated current-schema binding with SET NX and no\n// expiration.\nfunc (s *RedisSessionSandboxBindingStore) Create(\n\tctx context.Context,\n\tkey SessionSandboxKey,\n\tbinding SessionSandboxBinding,\n) (bool, error) {\n\tif err := binding.Validate(key); err != nil {\n\t\treturn false, err\n\t}\n\traw, err := json.Marshal(binding)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"encode sandbox binding: %w\", err)\n\t}\n\tcreated, err := s.client.SetNX(ctx, s.bindingKey(key), raw, 0).Result()\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"create sandbox binding: %w\", err)\n\t}\n\treturn created, nil\n}\n\n// DeleteIfMatch atomically deletes only the expected provider and sandbox ID.\nfunc (s *RedisSessionSandboxBindingStore) DeleteIfMatch(\n\tctx context.Context,\n\tkey SessionSandboxKey,\n\tprovider RemoteProvider,\n\tsandboxID string,\n) (bool, error) {\n\tif err := validateBindingMatch(key, provider, sandboxID); err != nil {\n\t\treturn false, err\n\t}\n\tdeleted, err := deleteBindingIfMatchScript.Run(\n\t\tctx,\n\t\ts.client,\n\t\t[]string{s.bindingKey(key)},","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/sandbox/session_binding_redis.go#L133-L169","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check Redis connectivity: redis-cli -h <host> -p <port> ping from the app host and verify REDIS_* env vars","Retry Create — the operation is idempotent thanks to SET NX semantics (returns created=false if already present)","Check redis-server logs for READONLY/maxmemory/ACL errors and fix the server-side condition","Increase the request context timeout and go-redis pool settings (PoolSize, dial/read/write timeouts) if errors correlate with load"],"exampleFix":"// before\ncreated, err := store.Create(ctx, key, binding)\nif err != nil { return err }\n// after: bounded retry for transient Redis failures\nvar created bool\nfor attempt := 0; attempt < 3; attempt++ {\n    created, err = store.Create(ctx, key, binding)\n    if err == nil { break }\n    select {\n    case <-ctx.Done():\n        return ctx.Err()\n    case <-time.After(time.Duration(1<<attempt) * 100 * time.Millisecond):\n    }\n}\nif err != nil { return fmt.Errorf(\"create binding after retries: %w\", err) }\nif !created { /* binding already exists — proceed or fail per business rule */ }","handlingStrategy":"retry","validationCode":"// verify Redis is reachable before critical write paths\nif err := rdb.Ping(ctx).Err(); err != nil {\n    return fmt.Errorf(\"redis unavailable before create: %w\", err)\n}","typeGuard":"func isTransientRedisError(err error) bool {\n    if err == nil { return false }\n    return errors.Is(err, context.DeadlineExceeded) ||\n        errors.Is(err, context.Canceled) == false &&\n        (errors.Is(err, io.EOF) || errors.Is(err, syscall.ECONNRESET) ||\n         strings.Contains(err.Error(), \"connection refused\") ||\n         strings.Contains(err.Error(), \"pool timeout\"))\n}","tryCatchPattern":"var created bool\nvar err error\nfor i := 0; i < 3; i++ {\n    if created, err = store.Create(ctx, key, binding); err == nil { break }\n    if !isTransientRedisError(err) { break }\n    select {\n    case <-ctx.Done(): return ctx.Err()\n    case <-time.After(backoff(i)):\n    }\n}\nif err != nil { return err }\nif !created { log.Printf(\"binding already existed for %s\", key.SessionID) }","preventionTips":["Configure go-redis pool size and timeouts for your concurrency level","Set up Redis health checks/readiness probes so traffic stops when Redis is down","Use stable Redis credentials and rotate with zero-downtime (dual-user window)","Prefer maxmemory-policy noeviction + capacity alerts over silent eviction of bindings"],"tags":["redis","network","availability","go"],"backgroundTag":"redis-unreachable","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}