Tencent/WeKnora · error
sandbox: %s backend must be constructed via NewSessionBoundM
Error message
sandbox: %s backend must be constructed via NewSessionBoundManager
What it means
DefaultManager.initializeSandbox refuses remote, session-scoped backends (Cube, E2B, Docker). These backends need per-session state that only SessionBoundManager owns via its authoritative session binding, so DefaultManager intentionally rejects them and points the caller at NewSessionBoundManager (which NewManagerFromType routes to automatically).
Source
Thrown at internal/sandbox/manager.go:56
}
return manager, nil
}
// initializeSandbox creates and configures the sandbox based on configuration
func (m *DefaultManager) initializeSandbox(ctx context.Context) error {
switch m.config.Type {
case SandboxTypeDisabled:
m.sandbox = &disabledSandbox{}
return nil
case SandboxTypeCube, SandboxTypeE2B, SandboxTypeDocker:
// Session-scoped remote backends are only reachable through
// SessionBoundManager, which owns the authoritative binding.
// DefaultManager exposes stateless semantics that cannot preserve
// per-session state, so we refuse the construction and let
// NewManagerFromType route the caller to NewSessionBoundManager.
return fmt.Errorf(
"sandbox: %s backend must be constructed via NewSessionBoundManager",
m.config.Type,
)
default:
return fmt.Errorf("unknown sandbox type: %s", m.config.Type)
}
}
// Execute runs a script using the configured sandbox
// It performs security validation before execution to prevent prompt injection attacks
func (m *DefaultManager) Execute(ctx context.Context, config *ExecuteConfig) (*ExecuteResult, error) {
m.mu.RLock()
sandbox := m.sandbox
m.mu.RUnlock()
if sandbox == nil {
return nil, ErrSandboxDisabledView on GitHub (pinned to 988cbb0330)
Solutions
- Use NewManagerFromType("cube"|"e2b"|"docker", dockerImage) which routes remote types to NewSessionBoundManager.
- Call NewSessionBoundManager directly with the required session binding configuration.
- If you only need the default manager, set config.Type to a stateless-supported type (e.g. local/disabled).
- Refactor call sites to pick the manager constructor based on backend type.
Example fix
// before
config := DefaultConfig(); config.Type = SandboxTypeE2B
mgr, err := NewManager(config)
// after
mgr, err := NewManagerFromType("e2b", "") // routes to NewSessionBoundManager Defensive patterns
Strategy: validation
Validate before calling
switch cfg.Type {
case SandboxTypeCube, SandboxTypeE2B, SandboxTypeDocker:
return errors.New("use NewManagerFromType / NewSessionBoundManager for this backend")
} Type guard
func needsSessionBound(t SandboxType) bool {
switch t {
case SandboxTypeCube, SandboxTypeE2B, SandboxTypeDocker:
return true
}
return false
} Try / catch
mgr, err := NewManager(cfg)
if err != nil && strings.Contains(err.Error(), "NewSessionBoundManager") {
mgr, err = NewManagerFromType(string(cfg.Type), "")
} Prevention
- Route remote backend types exclusively through NewManagerFromType
- Document that DefaultManager is for stateless backends only
- Add unit tests asserting constructor choice per sandbox type
When it happens
Trigger: Calling NewManager with a Config whose Type is SandboxTypeCube, SandboxTypeE2B, or SandboxTypeDocker; NewManager then fails during initializeSandbox.
Common situations: Choosing the wrong constructor: using NewManager instead of NewManagerFromType for remote sandbox types; older code written before session-bound managers existed; test code copying a config from a remote deployment into NewManager.
Related errors
- resolve remote sandbox for session: %w
- sandbox: no live sandbox for session %s
- sandbox: config is missing required fields
- cube remote client config is required
- cube api: create sandbox: empty sandboxID
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/b53b79efcb139cee.
Report an issue: GitHub.