Skip to content

bug(runtime): zellij Destroy swallows all ExitErrors, masking real failures as 'session already gone' #272

@fireddd

Description

@fireddd

Bug

zellij.Destroy treats ANY *exec.ExitError from zellij delete-session --force as "session already gone" and returns nil. But zellij can fail with non-zero exit for reasons other than "session not found" — corrupt socket, permission errors, version incompatibility, etc. This silently swallows real errors.

In the Create path (line ~141), a failed pre-cleanup Destroy is ignored, so the subsequent attach --create-background fails with a confusing "Session already exists" error instead of surfacing the real root cause.

Analyzed against: 96d1649 (current main)
Confidence: High — read the error handling path.

Root Cause

backend/internal/adapters/runtime/zellij/zellij.go:170-174:

func (z *Zellij) Destroy(ctx context.Context, handle ports.RuntimeHandle) error {
    if err := z.cmd(ctx, "delete-session", "--force", handle.ID); err != nil {
        var exitErr *exec.ExitError
        if errors.As(err, &exitErr) {
            return nil  // <-- treats ALL non-zero exits as "already gone"
        }
        return err
    }
    return nil
}

Reproduction

  1. Corrupt the zellij socket directory permissions:
    chmod 000 /tmp/zellij-*
  2. Call ao spawn — the Create path calls Destroy for pre-cleanup
  3. zellij delete-session --force fails with permission denied (ExitError)
  4. Destroy returns nil (swallowed)
  5. attach --create-background fails with a confusing error about the session already existing

Alternative: set ZELLIJ_CONFIG_DIR to an invalid path, causing zellij to fail on startup.

Impact

  • Real runtime failures are silently swallowed
  • Users see misleading secondary errors instead of the root cause
  • Debugging becomes harder: "Session already exists" when the real issue is a socket/permission problem

Suggested Fix

Check the stderr/exit message from zellij delete-session --force for the specific "session not found" pattern, rather than treating all non-zero exits as benign:

if errors.As(err, &exitErr) {
    if bytes.Contains(exitErr.Stderr, []byte("No session")) ||
       bytes.Contains(exitErr.Stderr, []byte("not found")) {
        return nil
    }
    return fmt.Errorf("zellij delete-session: %w", err)
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions