gastownhall/beads · error

list dep metadata: sourceID must not be empty

Error message

list dep metadata: sourceID must not be empty

What it means

Validation guard in listWithMetadata: the source issue ID whose dependency metadata is being listed is empty. Rather than issuing a doomed repository call, the use-case returns this explicit validation error.

Source

Thrown at internal/storage/domain/dependency.go:519

func (u *dependencyUseCaseImpl) ListByWispIDs(ctx context.Context, wispIDs []string, filter DepListFilter) (DepBulkResult, error) {
	return u.list(ctx, wispIDs, filter, true)
}

func (u *dependencyUseCaseImpl) ListWispWithIssueMetadata(ctx context.Context, wispID string, filter DepListFilter) ([]*types.IssueWithDependencyMetadata, error) {
	return u.listWithMetadata(ctx, wispID, filter, true)
}

func (u *dependencyUseCaseImpl) IterWispWithIssueMetadata(ctx context.Context, wispID string, filter DepListFilter) (storage.Iter[types.IssueWithDependencyMetadata], error) {
	return u.iterWithMetadata(ctx, wispID, filter, true)
}

func (u *dependencyUseCaseImpl) CountByWispID(ctx context.Context, wispID string, filter DepListFilter) (int64, error) {
	return u.countByID(ctx, wispID, filter, true)
}

func (u *dependencyUseCaseImpl) listWithMetadata(ctx context.Context, sourceID string, filter DepListFilter, useWisp bool) ([]*types.IssueWithDependencyMetadata, error) {
	if sourceID == "" {
		return nil, fmt.Errorf("list dep metadata: sourceID must not be empty")
	}
	out, err := u.depRepo.ListWithIssueMetadata(ctx, sourceID, DepListOpts{
		Types:         filter.Types,
		Direction:     filter.Direction,
		UseWispsTable: useWisp,
	})
	if err != nil {
		return nil, fmt.Errorf("list dep metadata: %w", err)
	}
	return out, nil
}

func (u *dependencyUseCaseImpl) iterWithMetadata(ctx context.Context, sourceID string, filter DepListFilter, useWisp bool) (storage.Iter[types.IssueWithDependencyMetadata], error) {
	if sourceID == "" {
		return nil, fmt.Errorf("iter dep metadata: sourceID must not be empty")
	}
	it, err := u.depRepo.IterWithIssueMetadata(ctx, sourceID, DepListOpts{
		Types:         filter.Types,

View on GitHub (pinned to 71377f2769)

Solutions

  1. Ensure the source issue is created/persisted and its ID fetched before listing metadata
  2. Add a caller-side empty check before invoking the list APIs
  3. Trace where the empty ID originates (usually an unsaved record or failed lookup)
  4. Use the issue object returned from Create/Get rather than a locally built struct

Example fix

// before
metas, err := u.ListWithIssueMetadata(ctx, issue.ID, filter) // issue.ID == ""
// after
if issue.ID == "" {
	return fmt.Errorf("issue not persisted")
}
metas, err := u.ListWithIssueMetadata(ctx, issue.ID, filter)
Defensive patterns

Strategy: validation

Validate before calling

if sourceID == "" {
	return fmt.Errorf("cannot list dep metadata: source ID is empty")
}

Type guard

func hasID(id string) bool { return id != "" }

Try / catch

metas, err := u.ListWithIssueMetadata(ctx, sourceID, filter)
if err != nil && strings.Contains(err.Error(), "sourceID must not be empty") {
	// caller bug: fix the ID source, not retryable
}

Prevention

When it happens

Trigger: Calling ListWithIssueMetadata or ListWispWithIssueMetadata with sourceID == "".

Common situations: Caller constructed an issue struct whose ID field was never populated (issue not yet persisted); a lookup returned empty and its value was passed through unguarded; string-typed ID variables defaulting to zero value.

Related errors


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