warpdotdev/warp · error · Error

cleanupOrphans: runId is required.

Error message

cleanupOrphans: runId is required.

What it means

cleanupOrphans() is a Figma plugin script that deletes every scene node, page, and variable tagged with plugin data key dsb_run_id equal to the given runId. Because deletion matches on an exact string, the function refuses to run without a runId; an undefined/empty value would make cleanup meaningless and hides the fact that the tagging step never supplied an id.

Source

Thrown at resources/bundled/mcp_skills/figma/figma-generate-library/scripts/cleanupOrphans.js:24

 * by a previous build run. This is safe cleanup: it uses plugin data tags,
 * never name-prefix matching, so it cannot accidentally delete user-owned nodes.
 *
 * Use this when a build run fails mid-way and you need to reset to a clean
 * slate before retrying. The function traverses the entire document looking
 * for `dsb_run_id` plugin data matching `runId`.
 *
 * Variables and variable collections are handled separately (they are not
 * scene nodes and cannot be discovered via node traversal).
 *
 * @param {string} runId - The dsb_run_id value to match (e.g. "ds-build-2024-001").
 * @returns {Promise<{
 *   removedCount: number,
 *   removedIds: string[]
 * }>}
 */
async function cleanupOrphans(runId) {
  if (!runId) {
    throw new Error('cleanupOrphans: runId is required.')
  }

  const removedIds = []
  const originalPage = figma.currentPage

  // --- Remove tagged scene nodes (pages, frames, components, etc.) ---
  // Collect pages to remove (can't remove during iteration)
  const pagesToRemove = []

  for (const page of figma.root.children) {
    if (page.getPluginData('dsb_run_id') === runId) {
      pagesToRemove.push(page)
      continue
    }

    // Traverse all nodes on this page
    await figma.setCurrentPageAsync(page)

View on GitHub (pinned to e72fd7aacb)

Solutions

  1. Pass the exact dsb_run_id string used when the artifacts were tagged, e.g. await cleanupOrphans('ds-build-2024-001')
  2. Trace where runId originates (manifest, client storage, parameters) and log it before the call to confirm it is a non-empty string
  3. Add a caller-side check that fails fast and names the missing key, so the bad value is caught before entering the plugin

Example fix

// before
await cleanupOrphans(manifest.runId) // undefined if manifest lacks runId

// after
const runId = manifest.dsb_run_id
if (typeof runId !== 'string' || runId === '') {
  throw new Error('manifest is missing dsb_run_id; cannot run cleanup')
}
await cleanupOrphans(runId)
Defensive patterns

Strategy: validation

Validate before calling

const runId = manifest.dsb_run_id
if (typeof runId !== 'string' || runId.trim() === '') {
  throw new Error(`manifest is missing dsb_run_id; refusing to run cleanup`)
}
await cleanupOrphans(runId)

Type guard

function isNonEmptyRunId(value: unknown): value is string {
  return typeof value === 'string' && value.trim().length > 0
}

Try / catch

try {
  const { removedCount } = await cleanupOrphans(runId)
  figma.notify(`Removed ${removedCount} nodes`)
} catch (err) {
  figma.notify(`cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { error: true })
  throw err
}

Prevention

When it happens

Trigger: Calling cleanupOrphans() with no argument, an empty string, or undefined/null — typically the orchestrator reads dsb_run_id from a manifest, environment, or figma.parameters and the key is absent, so undefined is passed through.

Common situations: A generate pipeline step that tags nodes with a run id (e.g. ds-build-2024-001) was skipped or stored the id under a different key; a new code path forgot to thread the runId parameter; the manifest uses run_id instead of dsb_run_id.

Related errors


AI-assisted analysis of warpdotdev/warp@e72fd7aacb (2026-08-16). Data as JSON: /api/errors/3210213c9627f7c5. Report an issue: GitHub.