{"record":{"id":"8260b8848d6c1807","repo":"gastownhall/beads","slug":"update-notes-and-append-notes-cannot-both-be-set","errorCode":null,"errorMessage":"update: notes and append notes cannot both be set","messagePattern":"update: notes and append notes cannot both be set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/uow/issue_operations.go","lineNumber":315,"sourceCode":"\tsetField(fields, \"description\", patch.Description)\n\tsetField(fields, \"design\", patch.Design)\n\tsetField(fields, \"acceptance_criteria\", patch.AcceptanceCriteria)\n\tsetField(fields, \"spec_id\", patch.SpecID)\n\tsetField(fields, \"await_id\", patch.AwaitID)\n\tsetField(fields, \"status\", patch.Status)\n\tsetField(fields, \"priority\", patch.Priority)\n\tif patch.IssueType.Set {\n\t\tfields[\"issue_type\"] = string(patch.IssueType.Value)\n\t}\n\tsetField(fields, \"assignee\", patch.Assignee)\n\tsetField(fields, \"owner\", patch.Owner)\n\tsetField(fields, \"closed_by_session\", patch.ClosedBySession)\n\tsetField(fields, \"estimated_minutes\", patch.EstimatedMinutes)\n\tsetField(fields, \"external_ref\", patch.ExternalRef)\n\tsetField(fields, \"due_at\", patch.DueAt)\n\tsetField(fields, \"defer_until\", patch.DeferUntil)\n\tif patch.Notes.Set && patch.AppendNotes.Set {\n\t\treturn domain.UpdateSpec{}, validationError(fmt.Errorf(\"update: notes and append notes cannot both be set\"))\n\t}\n\tsetField(fields, \"notes\", patch.Notes)\n\tif patch.AppendNotes.Set {\n\t\tfields[storageissueops.OpAppendNotes] = patch.AppendNotes.Value\n\t}\n\tif patch.Metadata.Replace.Set {\n\t\treplacement := json.RawMessage(\"{}\")\n\t\tif len(patch.Metadata.Replace.Value) > 0 {\n\t\t\treplacement = patch.Metadata.Replace.Value\n\t\t}\n\t\tif err := storageissueops.ValidateMetadataIfConfigured(replacement); err != nil {\n\t\t\treturn domain.UpdateSpec{}, validationError(err)\n\t\t}\n\t\tfields[\"metadata\"] = replacement\n\t} else {\n\t\tif patch.Metadata.Merge.Set {\n\t\t\tfields[storageissueops.OpMergeMetadata] = patch.Metadata.Merge.Value\n\t\t}","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/uow/issue_operations.go#L297-L333","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\npatch.Notes.Set = true; patch.Notes.Value = \"new\"\npatch.AppendNotes.Set = true; patch.AppendNotes.Value = \"more\" // rejected\n// after\npatch.Notes.Set = true; patch.Notes.Value = \"new\"\n// second update:\npatch2.AppendNotes.Set = true; patch2.AppendNotes.Value = \"more\"","handlingStrategy":"validation","validationCode":"if patch.Notes.Set && patch.AppendNotes.Set {\n    return errors.New(\"choose either notes replace or append, not both\")\n}","typeGuard":"func notesPatchValid(p domain.NotesPatch) bool { return !(p.Notes.Set && p.AppendNotes.Set) }","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"notes and append notes cannot both be set\") {\n    // split into two update calls and retry\n    return splitAndRetry()\n}","preventionTips":["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."],"tags":["validation","update","notes"],"backgroundTag":"mutually-exclusive-parameters","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}