{"record":{"id":"501498b7e5965121","repo":"sipeed/picoclaw","slug":"session-not-found","errorCode":null,"errorMessage":"session not found","messagePattern":"session not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/tools/session.go","lineNumber":30,"sourceCode":")\n\nconst maxOutputBufferSize = 1 * 1024 * 1024 // 1MB\n\nconst outputTruncateMarker = \"\\n... [output truncated, exceeded 1MB]\\n\"\n\n// PtyKeyMode represents arrow key encoding mode for PTY sessions.\n// Programs send smkx/rmkx sequences to switch between CSI and SS3 modes.\ntype PtyKeyMode uint8\n\nconst (\n\tPtyKeyModeCSI PtyKeyMode = iota // triggered by rmkx (\\x1b[?1l)\n\tPtyKeyModeSS3                   // triggered by smkx (\\x1b[?1h)\n)\n\nconst PtyKeyModeNotFound PtyKeyMode = 255\n\nvar (\n\tErrSessionNotFound = errors.New(\"session not found\")\n\tErrSessionDone     = errors.New(\"session already completed\")\n\tErrPTYNotSupported = errors.New(\"PTY is not supported on this platform\")\n\tErrNoStdin         = errors.New(\"no stdin available\")\n)\n\ntype ProcessSession struct {\n\tmu              sync.Mutex\n\tID              string\n\tPID             int\n\tCommand         string\n\tPTY             bool\n\tBackground      bool\n\tStartTime       int64\n\tExitCode        int\n\tStatus          string\n\tstdinWriter     io.Writer\n\tstdoutPipe      io.Reader\n\toutputBuffer    *bytes.Buffer","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/tools/session.go#L12-L48","documentation":"Sentinel error from the process-session manager in pkg/tools. It is returned by GetSession (session.go:235) when the registry holds no session under the given ID, and by killProcess (session.go:108) when the session's PID is <= 0, so there is no live OS process to act on. Callers in pkg/tools/shell.go (lines 753, 782, 818, 857, 1075) branch on errors.Is(err, ErrSessionNotFound) to convert it into a user-facing tool error rather than a crash.","triggerScenarios":"Passing a session ID that was never created, one from a previous run of the binary (registry is in-memory and resets on restart), or one whose session already exited and was removed. Also triggered by Kill() on a session whose PID field is 0 or negative.","commonSituations":"Agent tool invocations that cache a session ID across a daemon restart; racing a background process that finishes between listing sessions and writing to it; tests that construct ProcessSession structs directly without a PID.","solutions":["Re-list active sessions (the shell tool's session list) and use a currently running ID","Check the session Status field before calling Kill/Write; skip work if it is not \"running\"","If the ID came from a previous process lifetime, re-spawn the session instead of reusing the ID","In library code, handle it with errors.Is(err, tools.ErrSessionNotFound) and degrade gracefully instead of returning a raw error"],"exampleFix":"// before\nerr := sess.Kill()\nif err != nil {\n    return err // surfaces \"session not found\" to the user\n}\n\n// after\nerr := sess.Kill()\nif errors.Is(err, tools.ErrSessionNotFound) {\n    log.Printf(\"session %s already gone; nothing to kill\", id)\n    return nil\n}\nif err != nil {\n    return err\n}","handlingStrategy":"type-guard","validationCode":"if sess := manager.Get(id); sess == nil {\n    // re-list sessions and pick a live one instead of proceeding\n    ids := manager.ListIDs()\n    return fmt.Errorf(\"session %s gone; active: %v\", id, ids)\n}","typeGuard":"func isSessionNotFound(err error) bool {\n    return errors.Is(err, tools.ErrSessionNotFound)\n}","tryCatchPattern":"if err := sess.Kill(); err != nil {\n    if errors.Is(err, tools.ErrSessionNotFound) {\n        // already gone — treat as success in cleanup paths\n        return nil\n    }\n    return fmt.Errorf(\"kill session %s: %w\", id, err)\n}","preventionTips":["Never cache session IDs across daemon restarts; the registry is in-memory","Check sess.Status == \"running\" before Write or Kill","Always use errors.Is against the sentinels, never string matching on the message","Re-list sessions when an agent resumes after any pause"],"tags":["go","process","session","sentinel-error"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}