nexu-io/open-design · error · Error

leonardo.ai generation failed

Error message

leonardo.ai generation failed

What it means

Thrown when a Leonardo poll returns generation.status === 'FAILED'. This is the upstream terminal-failure signal — Leonardo accepted the job and then internally failed it (content-policy, model error, moderation). Distinct from [467] (transport failure) and [469] (no answer in time): this is a definitive negative answer.

Source

Thrown at apps/daemon/src/media/index.ts:2278

        'authorization': `Bearer ${credentials.apiKey}`,
      },
    }));
    
    if (!pollResp.ok) {
      throw new Error(`leonardo.ai poll ${pollResp.status}`);
    }
    
    const pollData = (await pollResp.json()) as Record<string, any>;
    const generation = pollData?.generations_by_pk;
    
    if (generation?.status === 'COMPLETE') {
      const images = generation?.generated_images;
      if (Array.isArray(images) && images.length > 0) {
        imageUrl = images[0]?.url;
        break;
      }
    } else if (generation?.status === 'FAILED') {
      throw new Error('leonardo.ai generation failed');
    }
  }
  
  if (!imageUrl) {
    throw new Error('leonardo.ai generation timed out after 2 minutes');
  }
  
  // Fetch the generated image
  const imgResp = await fetch(imageUrl, withMediaRequestInit(ctx));
  if (!imgResp.ok) {
    throw new Error(`leonardo.ai image fetch ${imgResp.status}`);
  }
  
  const bytes = Buffer.from(await imgResp.arrayBuffer());
  
  return {
    bytes,
    providerNote: `leonardo.ai/${ctx.model} · ${ctx.aspect} · ${bytes.length} bytes`,

View on GitHub (pinned to 5be4028344)

Solutions

  1. Rephrase the prompt to avoid content that may trip moderation; remove explicit/sensitive terms and retry.
  2. Try a different Leonardo model (e.g. switch from Phoenix to FLUX) — some failures are model-specific.
  3. Retry once — model crashes and intermittent content-filter false positives often succeed on a second attempt.
  4. If failures are persistent and the prompt is benign, file a Leonardo support ticket with the generationId.

Example fix

// before
if (generation?.status === 'FAILED') {
  throw new Error('leonardo.ai generation failed');
}

// after — surface upstream reason if present
if (generation?.status === 'FAILED') {
  const reason = generation?.error_message || generation?.failure_reason || 'no reason returned';
  throw new Error(`leonardo.ai generation failed: ${reason}`);
}
Defensive patterns

Strategy: try-catch

Try / catch

// Distinguish content-policy FAILED from transient model FAILED so the caller
// can retry the latter but not the former.
if (generation?.status === 'FAILED') {
  const reason = String(generation?.error_message || generation?.failure_reason || '').toLowerCase();
  const err = new Error(`leonardo.ai generation failed: ${reason || 'no reason returned'}`);
  (err as any).retryable = /timeout|temporary|server|unknown/.test(reason);
  throw err;
}

Prevention

When it happens

Trigger: Polling loop receives 200 with { generations_by_pk: { status: 'FAILED' } }. Commonly caused by prompts that trip Leonardo's content filters, unsupported parameter combinations, or upstream model crashes.

Common situations: Prompt contains content Leonardo's moderation blocks; requested model + size + guidance combination Leonardo's backend can't satisfy; transient Leonardo model crash; safety filter false-positive on benign prompt.

Related errors


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