gastownhall/beads · error

no issue found matching %q

Error message

no issue found matching %q

What it means

ResolvePartialID falls back to a substring search of the ID hash when exact matches fail. partialIDSearchPart validates the hash portion is searchable (e.g. non-empty, reasonable length); if it rejects the hash, no lookup can be performed and the function reports that no issue matches the input.

Source

Thrown at internal/utils/id_parser.go:129

		// Bare hash or prefix without hyphen: "a3f8e9", "07b8c8", "bda3f8e9" → all get prefix with hyphen added
		normalizedID = prefixWithHyphen + input
	}

	// Try exact match on normalized ID using SearchIssues (GH#942)
	normalizedFilter := types.IssueFilter{IDs: []string{normalizedID}}
	if issues, err := store.SearchIssues(ctx, "", normalizedFilter); err == nil && len(issues) > 0 {
		return issues[0].ID, nil
	}

	// If exact match failed, try substring search.
	// Use the hash part as a search query to leverage SQL-level filtering
	// (id LIKE %hash%) instead of loading ALL issues into memory.
	// On large databases (23k+ issues over MySQL wire protocol), loading all
	// issues took 60+ seconds; with SQL filtering it's near-instant.
	hashPart := strings.TrimPrefix(normalizedID, prefixWithHyphen)
	searchPart, ok := partialIDSearchPart(hashPart)
	if !ok {
		return "", fmt.Errorf("no issue found matching %q", input)
	}

	// Narrow projection: this loop only reads the .ID field, so use the
	// SearchIssueIDs path instead of SearchIssues. Avoids hydrating all
	// 45+ issue columns (including big TEXT fields like description, design,
	// notes, metadata, payload) only to discard them.
	filter := types.IssueFilter{}
	ids, err := store.SearchIssueIDs(ctx, searchPart, filter)
	if err != nil {
		return "", fmt.Errorf("failed to search issues: %w", err)
	}

	var matches []string
	var exactMatch string

	for _, id := range ids {
		// Check for exact full ID match first (case: user typed full ID with different prefix)
		if id == input {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Pass a real ID or hash fragment (e.g. "a3f8e9" or "bd-a3f8e9") instead of a bare prefix
  2. Trim/validate user input before calling: reject empty strings and prefix-only values
  3. Run `bd list` without an ID filter to find the correct issue, then retry with its real ID

Example fix

// before
id, err := utils.ResolvePartialID(ctx, store, "bd-") // no issue found matching "bd-"
// after
input := strings.TrimSpace(raw)
if input == "" || strings.TrimPrefix(input, "bd-") == "" { return fmt.Errorf("provide an issue ID") }
id, err := utils.ResolvePartialID(ctx, store, input)
Defensive patterns

Strategy: validation

Validate before calling

func searchableID(input, prefix string) bool {
	hash := strings.TrimPrefix(strings.TrimPrefix(input, prefix+"-"), prefix)
	return hash != ""
}
// reject prefix-only inputs before calling ResolvePartialID

Type guard

func looksLikeIssueID(input string) bool {
	input = strings.TrimSpace(input)
	return input != "" && strings.TrimPrefix(input, "bd-") != ""
}

Try / catch

id, err := utils.ResolvePartialID(ctx, store, input)
if err != nil {
	if strings.Contains(err.Error(), "no issue found matching") {
		return fmt.Errorf("%q is not a valid issue ID; run 'bd list' to find one", input)
	}
	return err
}

Prevention

When it happens

Trigger: Input that normalizes to an empty or invalid hash part — e.g. passing just the prefix "bd-", "bd" with no hash, or a string that strips to nothing after TrimPrefix of prefixWithHyphen.

Common situations: Users typing only a prefix in place of an ID; scripts passing empty or whitespace-ish tokens as issue IDs; cross-prefix inputs whose hash extraction yields nothing searchable.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/b6e174dd446d906f. Report an issue: GitHub.