gastownhall/beads · error
update: notes and append notes cannot both be set
Error message
update: notes and append notes cannot both be set
What it means
updateSpec rejects an UpdateRequest patch that sets both Notes (replace) and AppendNotes in the same update. The two operations are mutually exclusive — one overwrites the notes field, the other appends — so combining them is ambiguous. It is thrown as a validationError before any fields are persisted.
Source
Thrown at internal/storage/uow/issue_operations.go:315
setField(fields, "description", patch.Description)
setField(fields, "design", patch.Design)
setField(fields, "acceptance_criteria", patch.AcceptanceCriteria)
setField(fields, "spec_id", patch.SpecID)
setField(fields, "await_id", patch.AwaitID)
setField(fields, "status", patch.Status)
setField(fields, "priority", patch.Priority)
if patch.IssueType.Set {
fields["issue_type"] = string(patch.IssueType.Value)
}
setField(fields, "assignee", patch.Assignee)
setField(fields, "owner", patch.Owner)
setField(fields, "closed_by_session", patch.ClosedBySession)
setField(fields, "estimated_minutes", patch.EstimatedMinutes)
setField(fields, "external_ref", patch.ExternalRef)
setField(fields, "due_at", patch.DueAt)
setField(fields, "defer_until", patch.DeferUntil)
if patch.Notes.Set && patch.AppendNotes.Set {
return domain.UpdateSpec{}, validationError(fmt.Errorf("update: notes and append notes cannot both be set"))
}
setField(fields, "notes", patch.Notes)
if patch.AppendNotes.Set {
fields[storageissueops.OpAppendNotes] = patch.AppendNotes.Value
}
if patch.Metadata.Replace.Set {
replacement := json.RawMessage("{}")
if len(patch.Metadata.Replace.Value) > 0 {
replacement = patch.Metadata.Replace.Value
}
if err := storageissueops.ValidateMetadataIfConfigured(replacement); err != nil {
return domain.UpdateSpec{}, validationError(err)
}
fields["metadata"] = replacement
} else {
if patch.Metadata.Merge.Set {
fields[storageissueops.OpMergeMetadata] = patch.Metadata.Merge.Value
}View on GitHub (pinned to 71377f2769)
Solutions
- Send the append as its own follow-up update: first set notes, then append in a second call.
- Clear one of the two: either unset AppendNotes.Set or unset Notes.Set before issuing the update.
- If the intent was to append, populate only patch.AppendNotes; if replacing, only patch.Notes.
Example fix
// before patch.Notes.Set = true; patch.Notes.Value = "new" patch.AppendNotes.Set = true; patch.AppendNotes.Value = "more" // rejected // after patch.Notes.Set = true; patch.Notes.Value = "new" // second update: patch2.AppendNotes.Set = true; patch2.AppendNotes.Value = "more"
Defensive patterns
Strategy: validation
Validate before calling
if patch.Notes.Set && patch.AppendNotes.Set {
return errors.New("choose either notes replace or append, not both")
} Type guard
func notesPatchValid(p domain.NotesPatch) bool { return !(p.Notes.Set && p.AppendNotes.Set) } Try / catch
if err != nil && strings.Contains(err.Error(), "notes and append notes cannot both be set") {
// split into two update calls and retry
return splitAndRetry()
} Prevention
- Model updates as either replace OR append, never both.
- In CLI/UI layers, disable the notes field when append is chosen.
- Chain append edits as separate sequential update calls.
When it happens
Trigger: Calling Update with a patch where patch.Notes.Set is true and patch.AppendNotes.Set is true simultaneously (e.g. bd update with both --notes and --append-notes style inputs).
Common situations: CLI flag handling that always sets AppendNotes.Set when an append flag is present while also filling Notes; scripted updates built from merged option structs; a UI sending both fields.
Related errors
- %w: update title: %w
- %w: update priority: %w
- %w: update estimated_minutes: %w
- %w: invalid persistence mode %q
- %w: cannot combine metadata replacement with incremental met
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/8260b8848d6c1807.
Report an issue: GitHub.