nexu-io/open-design · error · Error

memory tree folders are derived and cannot be edited

Error message

memory tree folders are derived and cannot be edited

What it means

updateMemoryTreeNode was called with an id that starts with 'folder:'. Folder-prefixed ids are virtual/derived groupings in the memory tree UI — they represent categories, not editable entries. There is no .md file on disk for a folder node, so editing is rejected.

Source

Thrown at apps/daemon/src/memory.ts:487

  } catch {
    return null;
  }
  const { summary, body } = summarize(id, raw, stat.mtimeMs);
  return { ...summary, body };
}

function renderEntryFile(name, description, type, body, source) {
  const safeName = String(name || 'Untitled').replace(/\r?\n/g, ' ').trim();
  const safeDesc = String(description || '').replace(/\r?\n/g, ' ').trim();
  const safeType = isValidType(type) ? type : 'user';
  const safeSource = VALID_SOURCES.has(source) ? source : 'manual';
  const trimmedBody = String(body || '').replace(/^\s+/, '');
  return `---\nname: ${safeName}\ndescription: ${safeDesc}\ntype: ${safeType}\nsource: ${safeSource}\n---\n\n${trimmedBody}\n`;
}

export async function updateMemoryTreeNode(dataDir, id, patch) {
  if (typeof id !== 'string' || id.startsWith('folder:')) {
    throw new Error('memory tree folders are derived and cannot be edited');
  }
  const current = await readMemoryEntry(dataDir, id);
  if (!current) throw new Error('memory not found');
  const nextType = isValidType(patch?.type) ? patch.type : current.type;
  return upsertMemoryEntry(dataDir, {
    id,
    name:
      typeof patch?.name === 'string' && patch.name.trim()
        ? patch.name
        : current.name,
    description:
      typeof patch?.description === 'string'
        ? patch.description
        : current.description,
    type: nextType,
    body: typeof patch?.body === 'string' ? patch.body : current.body,
  });
}

View on GitHub (pinned to 5be4028344)

Solutions

  1. Only call updateMemoryTreeNode for leaf entry ids (those not starting with 'folder:')
  2. Filter out folder nodes from edit operations in the UI before dispatching
  3. Check !id.startsWith('folder:') before calling the update API

Example fix

// before — attempting to edit a derived folder node
updateMemoryTreeNode(dataDir, 'folder:profile', { name: '...' });

// after — guard against folder ids before calling
if (!id.startsWith('folder:')) {
  await updateMemoryTreeNode(dataDir, id, patch);
}
Defensive patterns

Strategy: validation

Validate before calling

function isEditableMemoryNode(id) {
  return typeof id === 'string' && !id.startsWith('folder:');
}

// Before calling updateMemoryTreeNode:
if (!isEditableMemoryNode(id)) {
  throw new Error(`Cannot edit derived folder node: ${id}`);
}

Type guard

function isEditableMemoryId(id: string): boolean {
  return typeof id === 'string' && !id.startsWith('folder:');
}

Prevention

When it happens

Trigger: The UI or API caller sends a PATCH/UPDATE request targeting a folder node id (e.g. 'folder:profile', 'folder:user'); the tree component doesn't distinguish between leaf entries and folder groupings when dispatching edits.

Common situations: Frontend tree component incorrectly allows an edit action on a folder/collapsed group node; API client copies a tree node id without checking whether it's a folder; a drag-and-drop or inline-edit handler fires on the wrong node type.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/e7c653a180f3fae6. Report an issue: GitHub.