nexu-io/open-design · error

delete proposal requires targetRef

Error message

delete proposal requires targetRef

What it means

Thrown by applyMemoryProposal() when proposal.action === 'delete' but proposal.targetRef is missing. A delete needs to know which memory entry to remove; without targetRef there is nothing to delete. Non-delete actions do not require targetRef (they can create a new entry).

Source

Thrown at apps/daemon/src/automation-proposals.ts:164

  const lines = text.split(/\r?\n/);
  const hasProposal = lines.some((line) => /^Proposal:\s*/i.test(line));
  const existingPackets = new Set(
    lines
      .map((line) => /^Source packet:\s*([A-Za-z0-9_-]+)\s*$/i.exec(line)?.[1])
      .filter((id): id is string => Boolean(id)),
  );
  const provenance: string[] = [];
  for (const packetId of proposal.sourcePacketIds ?? []) {
    if (!existingPackets.has(packetId)) provenance.push(`Source packet: ${packetId}`);
  }
  if (!hasProposal) provenance.push(`Proposal: ${proposal.id}`);
  if (provenance.length === 0) return text;
  return [text, '', ...provenance].join('\n');
}

async function applyMemoryProposal(dataDir: string, proposal: AutomationEvolutionProposal) {
  if (proposal.action === 'delete') {
    if (!proposal.targetRef) throw new Error('delete proposal requires targetRef');
    await deleteMemoryEntry(dataDir, proposal.targetRef);
    return { memoryId: proposal.targetRef, action: 'delete' };
  }

  const before = proposal.targetRef
    ? await readMemoryEntry(dataDir, proposal.targetRef)
    : null;
  const json = parseJsonPatchAfter(proposal);
  const metadata =
    proposal.metadata && typeof proposal.metadata === 'object' && !Array.isArray(proposal.metadata)
      ? proposal.metadata as Record<string, unknown>
      : {};
  const type = safeMemoryType(json.type ?? metadata.memoryType ?? before?.type);
  const body =
    typeof json.body === 'string'
      ? json.body
      : typeof json.markdown === 'string'
        ? json.markdown

View on GitHub (pinned to 5be4028344)

Solutions

  1. Update the proposal record to include targetRef pointing at the memory entry id/path to delete.
  2. If the target no longer exists, mark the proposal 'rejected' instead of applying it.
  3. When building memory-delete proposals, always set targetRef (and validate it before persisting).

Example fix

// before
{ targetKind: 'memory-node', action: 'delete', patch: { format: 'json', after: '{}' } }
// after
{ targetKind: 'memory-node', action: 'delete', targetRef: 'mem_abc123', patch: { format: 'json', after: '{}' } }
Defensive patterns

Strategy: validation

Validate before calling

if (proposal.action === 'delete' && !proposal.targetRef) {
  throw new Error('delete proposal requires targetRef');
}

Type guard

function isDeletableMemoryProposal(p: { action: string; targetRef?: string }): boolean {
  return p.action !== 'delete' || typeof p.targetRef === 'string' && p.targetRef.length > 0;
}

Prevention

When it happens

Trigger: Applying a memory-node proposal with action 'delete' that was created without a targetRef. The create-time validation does not enforce targetRef for memory deletes, so the error surfaces only at apply time.

Common situations: Agent emitted a delete proposal pointing at a target by name/id in metadata instead of targetRef; proposal was hand-crafted; ingestion pipeline built a delete from a stale reference that was never populated.

Related errors


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