sipeed/picoclaw · error

session not found

Error message

session not found

What it means

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.

Source

Thrown at pkg/tools/session.go:30

)

const maxOutputBufferSize = 1 * 1024 * 1024 // 1MB

const outputTruncateMarker = "\n... [output truncated, exceeded 1MB]\n"

// PtyKeyMode represents arrow key encoding mode for PTY sessions.
// Programs send smkx/rmkx sequences to switch between CSI and SS3 modes.
type PtyKeyMode uint8

const (
	PtyKeyModeCSI PtyKeyMode = iota // triggered by rmkx (\x1b[?1l)
	PtyKeyModeSS3                   // triggered by smkx (\x1b[?1h)
)

const PtyKeyModeNotFound PtyKeyMode = 255

var (
	ErrSessionNotFound = errors.New("session not found")
	ErrSessionDone     = errors.New("session already completed")
	ErrPTYNotSupported = errors.New("PTY is not supported on this platform")
	ErrNoStdin         = errors.New("no stdin available")
)

type ProcessSession struct {
	mu              sync.Mutex
	ID              string
	PID             int
	Command         string
	PTY             bool
	Background      bool
	StartTime       int64
	ExitCode        int
	Status          string
	stdinWriter     io.Writer
	stdoutPipe      io.Reader
	outputBuffer    *bytes.Buffer

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Re-list active sessions (the shell tool's session list) and use a currently running ID
  2. Check the session Status field before calling Kill/Write; skip work if it is not "running"
  3. If the ID came from a previous process lifetime, re-spawn the session instead of reusing the ID
  4. In library code, handle it with errors.Is(err, tools.ErrSessionNotFound) and degrade gracefully instead of returning a raw error

Example fix

// before
err := sess.Kill()
if err != nil {
    return err // surfaces "session not found" to the user
}

// after
err := sess.Kill()
if errors.Is(err, tools.ErrSessionNotFound) {
    log.Printf("session %s already gone; nothing to kill", id)
    return nil
}
if err != nil {
    return err
}
Defensive patterns

Strategy: type-guard

Validate before calling

if sess := manager.Get(id); sess == nil {
    // re-list sessions and pick a live one instead of proceeding
    ids := manager.ListIDs()
    return fmt.Errorf("session %s gone; active: %v", id, ids)
}

Type guard

func isSessionNotFound(err error) bool {
    return errors.Is(err, tools.ErrSessionNotFound)
}

Try / catch

if err := sess.Kill(); err != nil {
    if errors.Is(err, tools.ErrSessionNotFound) {
        // already gone — treat as success in cleanup paths
        return nil
    }
    return fmt.Errorf("kill session %s: %w", id, err)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/501498b7e5965121. Report an issue: GitHub.