{"record":{"id":"4f2ade2f9884b8c7","repo":"Tencent/WeKnora","slug":"sandbox-session-no-longer-exists","errorCode":null,"errorMessage":"sandbox session no longer exists","messagePattern":"sandbox session no longer exists","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/sandbox/session_lifecycle.go","lineNumber":30,"sourceCode":"\n\t\"github.com/Tencent/WeKnora/internal/types\"\n)\n\nconst (\n\tremoteMetadataTenantID       = \"weknora_tenant_id\"\n\tremoteMetadataSessionID      = \"weknora_session_id\"\n\tremoteMetadataBindingVersion = \"weknora_binding_version\"\n\tremoteMetadataProvider       = \"weknora_provider\"\n\n\t// remoteMetadataConfigID records which sandbox config created the sandbox.\n\t// Two configs in one workspace may share a provider account, so cleanup\n\t// must filter by config as well as tenant/session ownership.\n\tremoteMetadataConfigID = \"weknora_sandbox_config_id\"\n)\n\n// ErrSandboxSessionDeleted reports that the owning WeKnora session no longer\n// exists. Callers must not execute work with the returned nil handle.\nvar ErrSandboxSessionDeleted = errors.New(\"sandbox session no longer exists\")\n\n// SessionExistenceChecker checks the tenant-scoped durable session record.\ntype SessionExistenceChecker interface {\n\tSessionExists(context.Context, SessionSandboxKey) (bool, error)\n}\n\n// remoteSessionLifecycle coordinates one provider's persistent sandboxes using\n// an authoritative binding store. It contains no provider-native types.\ntype remoteSessionLifecycle struct {\n\tclient          RemoteSandboxClient\n\tbindings        SessionSandboxBindingStore\n\tsessionChecker  SessionExistenceChecker\n\tcreateRequest   RemoteCreateRequest\n\tcleanupTimeout  time.Duration\n\tsandboxConfigID string\n\tnow             func() time.Time\n}\n","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/sandbox/session_lifecycle.go#L12-L48","documentation":"ErrSandboxSessionDeleted is a sentinel error reporting that the durable WeKnora session owning a sandbox binding no longer exists. When the remote lifecycle manager detects the session was deleted, it cleans up the created sandbox/binding and returns this sentinel (often joined with cleanup errors via errors.Join) so callers never execute work with a nil handle.","triggerScenarios":"Resolving a binding or beginning a turn (resolveLocked/createAndBind path) when SessionExists reports false for the tenant/session key at internal/sandbox/session_lifecycle.go:161 or :375; the session was deleted concurrently or before sandbox creation finished.","commonSituations":"User deletes a session in another tab/API while a background job still runs work for it; stale queue messages referencing deleted sessions; race between session deletion and sandbox provisioning.","solutions":["Detect it with errors.Is(err, sandbox.ErrSandboxSessionDeleted) and skip/abandon the work unit gracefully instead of retrying.","Purge queued tasks whose session was deleted; check session existence before enqueueing work.","Treat it as an expected terminal state: log at info/warn, release the lifecycle lock, and drop cached bindings."],"exampleFix":"// before\nhandle, err := lifecycle.BeginTurn(ctx, key)\nif err != nil { return err } // retries forever on deleted sessions\n// after\nhandle, err := lifecycle.BeginTurn(ctx, key)\nif errors.Is(err, sandbox.ErrSandboxSessionDeleted) {\n    return nil // session gone; drop the job\n} else if err != nil { return err }","handlingStrategy":"try-catch","validationCode":"exists, err := checker.SessionExists(ctx, key)\nif err != nil { return err }\nif !exists { return fmt.Errorf(\"session %s gone; skip\", key.SessionID) }","typeGuard":null,"tryCatchPattern":"handle, err := lifecycle.BeginTurn(ctx, key)\nswitch {\ncase errors.Is(err, sandbox.ErrSandboxSessionDeleted):\n    log.Info(\"session deleted; dropping sandbox work\")\n    return nil\ncase err != nil:\n    return err\n}","preventionTips":["Always match the sentinel with errors.Is, never string comparison or err ==.","Acknowledge/purge queue messages for deleted sessions instead of retrying.","Check session existence before scheduling background sandbox work."],"tags":["go","sandbox","lifecycle","sentinel-error","session-deleted"],"backgroundTag":"resource-not-found","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}