gastownhall/beads · error · issueops.ErrValidation

%w: apply batch item %d has a metadata_ref with an empty key

Error message

%w: apply batch item %d has a metadata_ref with an empty key

What it means

Each entry in CreateItem.MetadataRefs is keyed by a metadata key; an empty-string map key is meaningless and rejected. This error fires when a create item's MetadataRefs map contains an entry whose key is "". Wraps issueops.ErrValidation.

Source

Thrown at internal/storage/batch_apply.go:201

			return err
		}
		item.DepAdd = &edge
		return nil
	}
	return fmt.Errorf("%w: apply batch item %d has unknown kind %q", issueops.ErrValidation, index, item.Kind)
}

// planApplyBatchCreate checks a create's metadata refs and records the row it
// mints as touched.
//
// A METADATA REF MAY NAME ANY KEY, including this item's own and one declared
// later. Every id is minted before any splice runs, so the direction cannot
// matter — see issueops.CreateItem.MetadataRefs. What it may not do is name a
// key no item declares.
func planApplyBatchCreate(item *issueops.CreateItem, index int, keyIndex map[string]int, touched map[string]bool) error {
	for metaKey, ref := range item.MetadataRefs {
		if metaKey == "" {
			return fmt.Errorf("%w: apply batch item %d has a metadata_ref with an empty key", issueops.ErrValidation, index)
		}
		if err := validateApplyRef(ref, index, "metadata_ref "+metaKey); err != nil {
			return err
		}
		if ref.Key == "" {
			continue
		}
		if _, ok := keyIndex[ref.Key]; !ok {
			return &issueops.RefError{Index: index, Member: "metadata_ref " + metaKey, Key: ref.Key}
		}
	}
	if item.Key != "" {
		touched[applyTouchKeyRef(issueops.Ref{Key: item.Key})] = true
	}
	if item.Issue != nil && item.Issue.ID != "" {
		touched[applyTouchKeyRef(issueops.Ref{ID: item.Issue.ID})] = true
	}
	return nil

View on GitHub (pinned to 71377f2769)

Solutions

  1. Filter out entries with empty metadata keys before building MetadataRefs
  2. Fix the upstream source so every metadata entry has a non-empty name
  3. Skip (or error at ingest) records missing a metadata key rather than adding them with ""

Example fix

// before
refs[k.Name] = issueops.Ref{Key: k.RefKey} // k.Name may be ""
// after
if k.Name == "" { return fmt.Errorf("metadata entry missing name") }
refs[k.Name] = issueops.Ref{Key: k.RefKey}
Defensive patterns

Strategy: validation

Validate before calling

for i, it := range items {
  if it.Create == nil { continue }
  for k := range it.Create.MetadataRefs {
    if k == "" { return fmt.Errorf("create item %d has empty metadata key", i) }
  }
}

Type guard

func hasEmptyMetaKey(it *issueops.CreateItem) bool {
  if it == nil { return false }
  _, bad := it.MetadataRefs[""]
  return bad
}

Try / catch

if err := store.PlanApplyBatch(plan); err != nil {
  if errors.Is(err, issueops.ErrValidation) && strings.Contains(err.Error(), "empty key") {
    // sanitize MetadataRefs keys and rebuild the plan
  }
  return err
}

Prevention

When it happens

Trigger: PlanApplyBatch with a create item built like MetadataRefs: map[string]issueops.Ref{"": {Key: "other"}} — e.g. dynamically populating the map from data where the metadata key was missing.

Common situations: Populating MetadataRefs by iterating over a source map that has empty keys; slicing/config where the metadata name column was blank; a nil/zero metadata name before insertion.

Related errors


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