oven-sh/bun · error

Failed to create gallery image definition: ${defResponse.sta

Error message

Failed to create gallery image definition: ${defResponse.status} ${await defResponse.text()}

What it means

While publishing a Windows image, the script PUTs an image-definition create to the Azure Shared Image Gallery REST API and tolerates only 200 and 409 (already exists). Any other non-OK status throws with the status code and response body — auth/RBAC problems, a missing gallery (404), or an invalid payload.

Source

Thrown at scripts/machine.mjs:1205

    method: "PUT",
    headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
    body: JSON.stringify({
      location: location,
      properties: {
        osType: "Windows",
        osState: "Generalized",
        hyperVGeneration: "V2",
        architecture: galleryArch,
        identifier: { publisher: "bun", offer: `${os}-${arch}-ci`, sku: imageDefName },
        features: [
          { name: "DiskControllerTypes", value: "SCSI, NVMe" },
          { name: "SecurityType", value: "TrustedLaunch" },
        ],
      },
    }),
  });
  if (!defResponse.ok && defResponse.status !== 409) {
    throw new Error(`Failed to create gallery image definition: ${defResponse.status} ${await defResponse.text()}`);
  }

  // Packer's azure-arm shared_image_gallery_destination always writes
  // image_version 1.0.0 and 409s if it already exists, so a re-run of
  // [publish images] would fail on every Windows variant that already
  // succeeded. Match the AWS path's deregister-then-recreate.
  // CAUTION: unlike the AWS path (which only deregisters after the new
  // create-image collides), this deletes the live version BEFORE Packer
  // has produced a replacement. If this job is canceled or dies mid-bake,
  // CI is left with no Windows image until a publish run completes.
  const versionPath = `${galleryPath}/versions/1.0.0`;
  const existing = await fetch(`https://management.azure.com${versionPath}?api-version=2024-03-03`, {
    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",

View on GitHub (pinned to 8c5296ac45)

Solutions

  1. Read the status and body embedded in the error message — they name the exact ARM failure
  2. 403/401: verify the principal has Contributor on the gallery's resource group and the token tenant
  3. 404: verify AZURE_GALLERY_NAME and AZURE_RESOURCE_GROUP secrets against the real gallery
  4. Re-run publish once permissions/secrets are corrected
Defensive patterns

Strategy: try-catch

Validate before calling

// Cheap pre-flight: the gallery must exist and the token must work
const gallery = await fetch(`https://management.azure.com${galleryPath}?api-version=2024-03-03`, {
  headers: { Authorization: `Bearer ${token}` },
});
if (gallery.status === 404) throw new Error('gallery/resource group not found — check AZURE_GALLERY_NAME secrets');
if (gallery.status === 401 || gallery.status === 403) throw new Error('token/RBAC problem on the gallery');

Try / catch

try {
  await createImageDefinition(/* ... */);
} catch (error) {
  // 409 is already handled upstream; anything else carries status+body — rethrow verbatim
  throw error;
}

Prevention

When it happens

Trigger: The token's principal lacks Contributor on the resource group/gallery (403); AZURE_GALLERY_NAME/AZURE_RESOURCE_GROUP secrets point at a nonexistent gallery (404); expired token (401); identifier/publisher fields rejected by validation (400).

Common situations: New CI service principal without gallery RBAC; wrong gallery name secret after migrating galleries; token fetched for the wrong tenant/subscription.

Related errors


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