usememos/memos · error
parent memo not found
Error message
parent memo not found
What it means
During a memo update, if the stored memo references a ParentUID, the helper re-fetches the parent by UID to inherit its visibility. A nil parent (UID set but no matching row) aborts with this error instead of silently keeping an orphaned reply thread. It is a data-integrity check on the parent reference.
Source
Thrown at server/router/api/v1/memo_update_helpers.go:51
return nil, nil, nil, errors.Wrap(err, "failed to list attachments")
}
relations, err := s.loadMemoRelations(ctx, memo)
if err != nil {
return nil, nil, nil, errors.Wrap(err, "failed to load memo relations")
}
memoMessage, err := s.convertMemoFromStore(ctx, memo, reactions, attachments, relations)
if err != nil {
return nil, nil, nil, errors.Wrap(err, "failed to convert memo")
}
var parentMemo *store.Memo
if memo.ParentUID != nil {
parentMemo, err = s.Store.GetMemo(ctx, &store.FindMemo{UID: memo.ParentUID})
if err != nil {
return nil, nil, nil, errors.Wrap(err, "failed to get parent memo")
}
if parentMemo == nil {
return nil, nil, nil, errors.New("parent memo not found")
}
memoMessage.Visibility = convertVisibilityFromStore(parentMemo.Visibility)
}
return memo, parentMemo, memoMessage, nil
}
func (s *APIV1Service) dispatchMemoUpdatedSideEffects(ctx context.Context, memo *store.Memo, parentMemo *store.Memo, memoMessage *v1pb.Memo) {
if err := s.DispatchMemoUpdatedWebhook(ctx, memoMessage); err != nil {
slog.Warn("Failed to dispatch memo updated webhook", slog.Any("err", err))
}
visibility := memo.Visibility
if parentMemo != nil {
visibility = parentMemo.Visibility
}
s.SSEHub.Broadcast(&SSEEvent{
Type: SSEEventMemoUpdated,View on GitHub (pinned to 14d757ce1f)
Solutions
- Re-fetch the parent (GetMemo with the ParentUID) and if missing, clear the child's parent field (set parent to empty/unset) before updating.
- When implementing memo deletion, detach children (clear their parent) in the same flow.
- Repair dangling references directly in the database or via a script if the corruption already exists.
Example fix
// before
await memoClient.updateMemo({ memo: { name, content, ...staleMemo } }); // stale parent set
// after
let parent;
try { parent = await memoClient.getMemo({ name: parentName }); } catch { parent = null; }
const memo = parent ? { ...staleMemo } : { ...staleMemo, parent: undefined }; Defensive patterns
Strategy: validation
Validate before calling
if (memo.parent) {
const parent = await memoClient.getMemo({ name: memo.parent }).catch(() => null);
if (!parent) memo = { ...memo, parent: undefined }; // detach orphaned reference before update
} Try / catch
try { await memoClient.updateMemo({ memo }); }
catch (e) {
if (e.message.includes('parent memo not found')) {
await memoClient.updateMemo({ memo: { ...memo, parent: undefined } });
return;
}
throw e;
} Prevention
- When deleting a memo, clear parent references on its children in the same operation/flow.
- Treat parent references as owned data: validate them on read in the UI.
- After DB restores or imports, run a consistency check for dangling parent UIDs.
When it happens
Trigger: Updating a memo whose parent_id/ParentUID points to a deleted memo; parent deleted in another session while the child edit is in flight; database restored or partially migrated leaving dangling parent references.
Common situations: Deleting a parent memo without cascade-detaching children; multi-tab editing races; imports that preserved parent UIDs from a different instance.
Related errors
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/1fd69f1fe4a1e33a.
Report an issue: GitHub.