gastownhall/beads · error
no slot %q on %s: key not found
Error message
no slot %q on %s: key not found
What it means
The issue has valid metadata JSON, but the requested slot key is absent from that JSON object. SlotGet uses the comma-ok map lookup and returns this descriptive error instead of an empty string, distinguishing 'metadata exists, key missing' from the no-metadata case.
Source
Thrown at internal/storage/dolt/slots.go:107
// Returns an error if the issue has no metadata or the key is not found.
func (s *DoltStore) SlotGet(ctx context.Context, issueID, key string) (string, error) {
issue, err := s.GetIssue(ctx, issueID)
if err != nil {
return "", fmt.Errorf("getting issue %s: %w", issueID, err)
}
if len(issue.Metadata) == 0 {
return "", fmt.Errorf("no slot %q on %s: no metadata", key, issueID)
}
metadata := make(map[string]interface{})
if err := json.Unmarshal(issue.Metadata, &metadata); err != nil {
return "", fmt.Errorf("parsing metadata for %s: %w", issueID, err)
}
val, ok := metadata[key]
if !ok {
return "", fmt.Errorf("no slot %q on %s: key not found", key, issueID)
}
switch v := val.(type) {
case string:
return v, nil
default:
// Non-string values are returned as JSON
raw, err := json.Marshal(v)
if err != nil {
return "", fmt.Errorf("marshaling slot value for %s.%s: %w", issueID, key, err)
}
return string(raw), nil
}
}
// SlotClear removes a metadata key from an issue.
// It is not an error to clear a key that doesn't exist.
//View on GitHub (pinned to 71377f2769)
Solutions
- Check the key spelling and exact case against what SlotSet wrote.
- Set the slot first (SlotSet) or fall back to a default value in the caller.
- List the issue's metadata (query the metadata column) to see which keys exist.
Example fix
// before val, err := store.SlotGet(ctx, id, "Owner") // key was set as "owner" // after val, err := store.SlotGet(ctx, id, "owner") // exact key as stored
Defensive patterns
Strategy: validation
Validate before calling
issue, _ := store.GetIssue(ctx, issueID)
var m map[string]interface{}
if json.Unmarshal(issue.Metadata, &m) == nil {
if _, ok := m[key]; !ok {
// key absent; set it or use a default before SlotGet
}
} Type guard
func slotExists(issue *storage.Issue, key string) bool {
var m map[string]interface{}
if json.Unmarshal(issue.Metadata, &m) != nil {
return false
}
_, ok := m[key]
return ok
} Try / catch
val, err := store.SlotGet(ctx, id, key)
if err != nil && strings.Contains(err.Error(), "key not found") {
val = defaultValue
} Prevention
- Define slot keys as constants to avoid typos and case mismatches.
- Set optional slots explicitly (even to an empty value) before reading.
- Remember SlotClear is lossless removal — re-set keys you still need.
When it happens
Trigger: Calling SlotGet with a key that was never set via SlotSet/MergeMetadata, or one that was already removed by SlotClear.
Common situations: Typo in the slot key (case-sensitive lookup); SlotClear ran earlier; reading an optional slot on issues where only some have it set.
Related errors
- no slot %q on %s: no metadata
- record repo_id: %w
- record clone_id: %w
- record last_import_time: %w
- getting issue %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/4c161989bd04d0d0.
Report an issue: GitHub.