gastownhall/beads · warning · memoryops.ErrValidation

memory key must not be empty

Error message

memory key must not be empty

What it means

ValidateKey requires that an explicitly supplied memory key names something: empty or whitespace-only keys are rejected with memoryops.ErrValidation. Keys that pass are returned UNCHANGED — surrounding space is deliberately preserved because a user may genuinely hold such a key via bd remember --key.

Source

Thrown at internal/memoryapi/memoryapi.go:96

// reading since the command shipped, and the sentinel is what code classifies
// on.
func ValidateContent(content string) error {
	if strings.TrimSpace(content) == "" {
		return fmt.Errorf("%w: memory content cannot be empty", memoryops.ErrValidation)
	}
	return nil
}

// ValidateKey checks a key a caller wants to read or remove, and returns it
// UNCHANGED.
//
// Unchanged is the whole point: `bd remember --key` accepts any string, so a
// key differing from another only by surrounding space is a key someone may
// genuinely hold, and trimming it here would answer a different question from
// the one asked. The only rule is that a key has to name something.
func ValidateKey(key string) (string, error) {
	if strings.TrimSpace(key) == "" {
		return "", fmt.Errorf("%w: memory key must not be empty", memoryops.ErrValidation)
	}
	return key, nil
}

// ResolveKey answers which key a Remember lands under: the caller's if it gave
// one, otherwise the derivation of the content.
//
// It is one function rather than a derivation at each implementation because
// the ORDER matters and is invisible once it is spelled twice: an explicit key
// is used verbatim even when it is content-shaped, and content is only ever
// derived from when no key was given. The refusal for content that derives to
// nothing lives here too, so a caller cannot get a row under the empty key by
// reaching the write through a body that forgot to check.
func ResolveKey(key, content string) (string, error) {
	if err := ValidateContent(content); err != nil {
		return "", err
	}
	if key != "" {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Supply a non-empty key via --key or the key argument.
  2. Check the variable feeding --key is set and non-blank.
  3. If unsure of a key, omit --key and let bd derive one from the content.

Example fix

// before
key, err := memoryapi.ValidateKey(os.Args[2]) // may be ""
// after
if strings.TrimSpace(os.Args[2]) == "" {
    return fmt.Errorf("--key requires a value")
}
key, err := memoryapi.ValidateKey(os.Args[2])
Defensive patterns

Strategy: validation

Validate before calling

if strings.TrimSpace(key) == "" {
    return fmt.Errorf("--key requires a non-empty value")
}

Type guard

func hasKey(s string) bool { return strings.TrimSpace(s) != "" }

Try / catch

key, err := memoryapi.ValidateKey(providedKey)
if err != nil {
    if errors.Is(err, memoryops.ErrValidation) {
        return fmt.Errorf("provide --key or omit it to derive from content")
    }
    return err
}

Prevention

When it happens

Trigger: Calling ValidateKey("") or a whitespace-only string; bd remember --key " "; ResolveKey delegating to ValidateKey with a blank explicit key.

Common situations: --key flag fed from an unset shell variable; script passing an empty placeholder key; copy-pasted key that lost its content in transit.

Related errors


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