oven-sh/bun · error

Failed to delete existing gallery image version: ${del.statu

Error message

Failed to delete existing gallery image version: ${del.status} ${await del.text()}

What it means

The DELETE of the existing gallery image version returned a non-OK, non-404 status (404 means 'already gone' and is fine). The message embeds the HTTP status and response text: 401/403 = auth or RBAC, 409 = another conflicting operation on the same version.

Source

Thrown at scripts/machine.mjs:1236

    headers: { Authorization: `Bearer ${token}` },
  });
  if (existing.ok) {
    console.log(`[packer] Deleting existing gallery image version 1.0.0 of ${imageDefName} before re-publish`);
    const del = await fetch(`https://management.azure.com${versionPath}?api-version=2024-03-03`, {
      method: "DELETE",
      headers: { Authorization: `Bearer ${token}` },
    });
    if (del.status === 202) {
      const op = del.headers.get("Azure-AsyncOperation") ?? del.headers.get("Location");
      for (let i = 0; op && i < 120; i++) {
        await new Promise(r => setTimeout(r, 10_000));
        const poll = await fetch(op, { headers: { Authorization: `Bearer ${token}` } });
        const body = await poll.json().catch(() => ({}));
        if (body.status === "Succeeded") break;
        if (body.status === "Failed") throw new Error(`Delete of ${versionPath} failed: ${JSON.stringify(body)}`);
      }
    } else if (!del.ok && del.status !== 404) {
      throw new Error(`Failed to delete existing gallery image version: ${del.status} ${await del.text()}`);
    }
  }

  // Install Packer if not available
  const packerBin = await ensurePacker();

  // Initialize plugins
  console.log("[packer] Initializing plugins...");
  await spawnSafe([packerBin, "init", templateDir], { stdio: "inherit" });

  // Build the image
  console.log(`[packer] Building ${templateName} image: ${imageDefName}`);
  const packerArgs = [
    packerBin,
    "build",
    "-only",
    `azure-arm.${templateName}`,
    "-var",

View on GitHub (pinned to 8c5296ac45)

Solutions

  1. Map the embedded status: 401/403 fix credentials/RBAC, 409 wait for the in-flight operation then retry
  2. Serialize the publish pipeline so only one job deletes a given version
  3. Re-run the publish job — the delete-and-recreate path is designed to be idempotent
Defensive patterns

Strategy: try-catch

Validate before calling

if (!token) throw new Error('no Azure token — call getAzureToken before deleting versions');
const probe = await fetch(`https://management.azure.com${versionPath}?api-version=2024-03-03`, {
  headers: { Authorization: `Bearer ${token}` },
});
if (probe.status === 401 || probe.status === 403) throw new Error('token/RBAC cannot delete gallery versions');

Try / catch

try {
  await deleteVersion(versionPath);
} catch (error) {
  const msg = String(error);
  if (/ 409 /.test(msg)) {
    // wait for the in-flight operation, then retry the delete once
  } else {
    throw error; // 401/403 need credential/RBAC fixes, not retries
  }
}

Prevention

When it happens

Trigger: Token expired between auth and delete; principal lacking Microsoft.Compute/galleries/images/versions/delete; a concurrent delete/replica operation on version 1.0.0 returning 409.

Common situations: Overlapping publish jobs deleting the same version; RBAC drift after principal rotation; long bakes letting the bearer token age out.

Related errors


AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16). Data as JSON: /api/errors/dd862a0e23979926. Report an issue: GitHub.