Tencent/WeKnora · error
decode sandbox binding: %w
Error message
decode sandbox binding: %w
What it means
This error is returned by RedisSessionSandboxBindingStore.Get when the JSON value stored under the session's binding key in Redis cannot be unmarshaled into SessionSandboxBinding. The binding key holds JSON with no TTL, so the store throws this when the stored value is corrupt, truncated, written by a different schema version, or not JSON at all (e.g. hand-edited or written by another tool). It wraps the underlying json.Unmarshal error with 'decode sandbox binding: %w'.
Source
Thrown at internal/sandbox/session_binding_redis.go:127
// Get returns the current binding, or nil when the session is unbound.
func (s *RedisSessionSandboxBindingStore) Get(
ctx context.Context,
key SessionSandboxKey,
) (*SessionSandboxBinding, error) {
if err := key.Validate(); err != nil {
return nil, err
}
raw, err := s.client.Get(ctx, s.bindingKey(key)).Bytes()
if errors.Is(err, redis.Nil) {
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("get sandbox binding: %w", err)
}
var binding SessionSandboxBinding
if err := json.Unmarshal(raw, &binding); err != nil {
return nil, fmt.Errorf("decode sandbox binding: %w", err)
}
if err := binding.Validate(key); err != nil {
return nil, fmt.Errorf("validate sandbox binding: %w", err)
}
return &binding, nil
}
// 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)View on GitHub (pinned to 988cbb0330)
Solutions
- Run redis-cli GET 'weknora:sandbox:session:{<namespace>:<tenantID>:<sessionID>}:binding' and inspect whether the value is valid JSON matching the current SessionSandboxBinding schema
- If the value is corrupt or legacy, delete it with DEL — Get then returns (nil, nil) as an unbound session and the next resolve recreates the binding
- Roll out the current build fully so no old process writes legacy-format bindings mid-flight
- If corruption is recurring, check for external writers/scripts touching the weknora:sandbox:* key space and check Redis persistence health (AOF/RDB integrity)
Example fix
// before: error surfaces to caller as opaque decode failure
binding, err := store.Get(ctx, key)
if err != nil { return err }
// after: recover by treating an undecodable binding as unbound and recreating it
binding, err := store.Get(ctx, key)
if err != nil {
if strings.Contains(err.Error(), "decode sandbox binding") {
_ = store.DeleteIfMatch(ctx, key, provider, sandboxID)
created, cerr := store.Create(ctx, key, SessionSandboxBinding{Provider: provider, SandboxID: sandboxID})
if cerr != nil { return cerr }
_ = created
binding, err = store.Get(ctx, key)
}
if err != nil { return err }
} Defensive patterns
Strategy: try-catch
Validate before calling
// best-effort pre-check that the stored value is parseable JSON before relying on Get
func bindingLooksValid(ctx context.Context, rdb *redis.Client, key string) bool {
raw, err := rdb.Get(ctx, "weknora:sandbox:session:{"+key+"}:binding").Bytes()
return err == nil && json.Valid(raw)
} Type guard
func isDecodeBindingError(err error) bool {
return err != nil && strings.Contains(err.Error(), "decode sandbox binding")
} Try / catch
binding, err := store.Get(ctx, key)
if isDecodeBindingError(err) {
// corrupt record: treat session as unbound and let resolve recreate the binding
log.Printf("corrupt binding for %s: %v", key.SessionID, err)
binding, err = nil, nil
} else if err != nil {
return fmt.Errorf("get binding: %w", err)
} Prevention
- Never SET weknora:sandbox:* keys manually or from scripts outside the store API
- Keep SessionSandboxBinding schema changes backward-compatible during rolling upgrades
- Add a startup smoke test that Get/Create/Get a throwaway session key
- Monitor decode-failure logs — a spike indicates external writers or persistence corruption
When it happens
Trigger: Calling Get(ctx, key) when the Redis string at weknora:sandbox:session:{<ns>:<tenant>:<session>}:binding is corrupt/truncated JSON, was written by an older or newer schema version whose fields no longer unmarshal, was manually overwritten with non-JSON data, or contains types incompatible with the SessionSandboxBinding struct (e.g. StaleAt not a timestamp).
Common situations: Version-skew during a rolling upgrade where an older build wrote a legacy binding format; an operator or cleanup script SET the key directly with wrong content; Redis persistence restored a truncated value after a crash; manual inspection tools (redis-cli) accidentally modified the key.
Related errors
- WEKNORA_REDIS_NAMESPACE must not contain braces
- WEKNORA_REDIS_NAMESPACE must not contain control characters
- get sandbox binding: %w
- validate sandbox binding: %w
- encode sandbox binding: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/1dde49104ffdbf56.
Report an issue: GitHub.