charmbracelet/crush · error

session not found: %s

Error message

session not found: %s

What it means

resolveSessionID lets users pass a full session ID or a unique hash prefix. After scanning all sessions, if no session's ID (or hash prefix) matches the given argument, this 'session not found' error is returned. It is a user-input error, not a system failure.

Source

Thrown at internal/cmd/session.go:238

		return s, nil
	}

	// List all sessions and check for hash matches
	sessions, err := svc.List(ctx)
	if err != nil {
		return session.Session{}, err
	}

	var matches []session.Session
	for _, s := range sessions {
		hash := session.HashID(s.ID)
		if hash == id || strings.HasPrefix(hash, id) {
			matches = append(matches, s)
		}
	}

	if len(matches) == 0 {
		return session.Session{}, fmt.Errorf("session not found: %s", id)
	}

	if len(matches) == 1 {
		return matches[0], nil
	}

	// Ambiguous - show matches like Git does
	var sb strings.Builder
	fmt.Fprintf(&sb, "session ID '%s' is ambiguous. Matches:\n\n", id)
	for _, m := range matches {
		hash := session.HashID(m.ID)
		created := time.Unix(m.CreatedAt, 0).Format("2006-01-02")
		// Keep title on one line by replacing newlines with spaces, and truncate.
		title := strings.ReplaceAll(m.Title, "\n", " ")
		title = ansi.Truncate(title, 50, "…")
		fmt.Fprintf(&sb, "  %s... %q (created %s)\n", hash[:12], title, created)
	}
	sb.WriteString("\nUse more characters or the full hash")

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Run `crush session list` (or with --json) to see valid session IDs and copy one exactly
  2. Check you are pointing at the same --data-dir used when the session was created
  3. Verify the prefix is long enough and matches at least one session hash
  4. If ambiguous vs missing confusion matters, note that multiple matches raise a separate ambiguity error — this one means zero matches

Example fix

// before
crush session show abc12
// after
crush session list            # find the correct ID
crush session show abc123def456...   # use full/valid ID
Defensive patterns

Strategy: validation

Validate before calling

// validate the ID against the session list before resolving
list, _ := svc.sessions.List(ctx)
id := args[0]
found := false
for _, s := range list {
    if s.ID == id || strings.HasPrefix(strings.TrimPrefix(s.ID, "session_"), id) {
        found = true
        break
    }
}
if !found {
    return fmt.Errorf("unknown session %q; run 'crush session list' to see valid IDs", id)
}

Try / catch

sess, err := resolveSessionID(ctx, svc.sessions, args[0])
if err != nil {
    var nfErr *NotFoundError
    if errors.As(err, &nfErr) {
        fmt.Fprintf(os.Stderr, "No session matching %q. Try 'crush session list'.\n", args[0])
        os.Exit(1)
    }
    return err
}

Prevention

When it happens

Trigger: `crush session show|delete|rename <id>` called with an ID/prefix that matches zero sessions — typo, session already deleted, or wrong data directory (different DB).

Common situations: Copy-pasting an ID from another machine's data dir; truncating a hash prefix so it matches nothing; referencing a session deleted earlier; case-sensitivity mismatch in the prefix.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/fbda30123b102bdb. Report an issue: GitHub.