Tencent/WeKnora · error

encode sandbox binding: %w

Error message

encode sandbox binding: %w

What it means

Returned by RedisSessionSandboxBindingStore.Create when json.Marshal of the SessionSandboxBinding fails before the SET NX is issued. Marshal of a plain struct rarely fails, so this almost always indicates the binding contains a value JSON cannot represent (e.g. a channel, func, or cyclic value added to the struct) or a custom MarshalJSON that errors. Wrapped as 'encode sandbox binding: %w'.

Source

Thrown at internal/sandbox/session_binding_redis.go:147

	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)
	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
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Inspect the wrapped %w error — it names the unsupported type; remove or replace the non-serializable field on SessionSandboxBinding
  2. Add a field with json:"-" if it is runtime-only and must not be persisted
  3. Ensure any custom MarshalJSON handles zero/nil values gracefully
  4. Unit-test Create with a fully populated binding to catch serialization regressions before deployment

Example fix

// before
type SessionSandboxBinding struct {
    Provider  RemoteProvider
    SandboxID string
    Runtime   *SandboxRuntime // contains a channel: json.Marshal fails
}
// after
type SessionSandboxBinding struct {
    Provider  RemoteProvider
    SandboxID string
    Runtime   *SandboxRuntime `json:"-"` // runtime-only, not persisted
}
Defensive patterns

Strategy: validation

Validate before calling

// fail fast in tests/CI when SessionSandboxBinding gains non-serializable fields
func TestBindingIsJSONEncodable(t *testing.T) {
    b := sandbox.SessionSandboxBinding{Provider: provider, SandboxID: "sbx-123"}
    if _, err := json.Marshal(b); err != nil {
        t.Fatalf("binding not encodable: %v", err)
    }
}

Try / catch

created, err := store.Create(ctx, key, binding)
if err != nil && strings.Contains(err.Error(), "encode sandbox binding") {
    return fmt.Errorf("programming error: binding type not serializable: %w", err)
}

Prevention

When it happens

Trigger: Calling Create(ctx, key, binding) where the binding (or a nested field added to SessionSandboxBinding) contains an unsupported type — channels, funcs, cycles — or implements MarshalJSON returning an error.

Common situations: A developer extended SessionSandboxBinding with a non-serializable field (e.g. *time.Ticker, sync primitives, interface holding a channel); a custom MarshalJSON implementation panics/errors on zero values; struct embedding pulled in unserializable fields.

Related errors


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