nexu-io/open-design · error · Error

Vela image ${command} response is missing asset_id

Error message

Vela image ${command} response is missing asset_id

What it means

Thrown after parsing the Vela image gen/edit JSON response when asset.asset_id is empty or missing. The asset_id is the primary identifier for the generated asset; without it the daemon cannot reference, fetch, or attribute the result. The command name (gen or edit) is interpolated.

Source

Thrown at apps/daemon/src/media/vela.ts:390

      ...stagedImageRefs.flatMap((image) => ['--image', image.abs]),
      ...(profile
        ? ['--aspect-ratio', profile.aspectRatio, '--resolution', profile.resolution]
        : []),
      ...quality,
      '--output',
      outputPath,
      '--json',
    ];
    const stdout = await runCommand(args, {
      ...velaWorkspaceCommandOptions(input.workspaceId),
      timeoutMs: VELA_IMAGE_TIMEOUT_MS,
    });
    const asset = parseJsonObject(stdout, `image ${command}`);
    const assetId = nonEmptyString(asset.asset_id);
    const status = nonEmptyString(asset.status);
    const kind = nonEmptyString(asset.kind);
    const mime = nonEmptyString(asset.mime_type);
    if (!assetId) throw new Error(`Vela image ${command} response is missing asset_id`);
    if (status !== 'ready') {
      throw new Error(`Vela image ${command} returned non-ready asset status ${status ?? 'missing'}`);
    }
    if (kind !== 'image') {
      throw new Error(`Vela image ${command} returned unexpected kind ${kind ?? 'missing'}`);
    }
    if (!mime?.startsWith('image/')) {
      throw new Error(`Vela image ${command} returned invalid mime_type ${mime ?? 'missing'}`);
    }
    const bytes = await readNonEmptyOutput(outputPath, `image ${command}`);
    return {
      bytes,
      // The tier is part of what the user was charged for, so name it when it
      // was chosen and say so plainly when the server's default decided.
      providerNote: `vela/${wireModel} · ${
        profile ? `${profile.aspectRatio} ${profile.resolution}` : 'model default profile'
      } · ${requestedQuality ?? 'model default quality'} · ${bytes.length} bytes`,
      suggestedExt: extensionForImageMime(mime),

View on GitHub (pinned to 5be4028344)

Solutions

  1. Run the same Vela image command with --json directly and inspect the asset object shape
  2. Upgrade or pin the Vela CLI version to one whose schema matches
  3. Check Vela stderr/logs for an upstream generation failure that produced a malformed response
  4. Update the response parser if Vela renamed the field
Defensive patterns

Strategy: try-catch

Validate before calling

function hasAssetId(asset: Record<string, unknown>): boolean {
  return typeof asset.asset_id === 'string' && asset.asset_id.trim().length > 0;
}

const asset = parseJsonObject(stdout, label);
if (!hasAssetId(asset)) {
  throw new Error(`Vela ${label} response missing asset_id — check CLI version/schema`);
}

Type guard

function hasVelaAssetId(asset: unknown): asset is { asset_id: string } {
  return typeof asset === 'object' && asset !== null
    && typeof (asset as { asset_id?: unknown }).asset_id === 'string'
    && (asset as { asset_id: string }).asset_id.trim().length > 0;
}

Try / catch

try {
  const asset = parseJsonObject(stdout, label);
  if (!hasVelaAssetId(asset)) throw new Error(`Vela ${label} response is missing asset_id`);
} catch (err) {
  // log full stdout for schema diagnosis, then rethrow or map to a retry
}

Prevention

When it happens

Trigger: Vela's image gen/edit returned a JSON object (parsed successfully) but the asset_id field is absent, null, or whitespace-only (nonEmptyString returns null).

Common situations: Vela CLI version changed the response schema and renamed asset_id; partial/failed generation returned a status envelope without the id; upstream bug.

Related errors


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