{"record":{"id":"8a12814137069573","repo":"nexu-io/open-design","slug":"unsupported-leonardo-ai-model-ctx-model","errorCode":null,"errorMessage":"unsupported leonardo.ai model: ${ctx.model}","messagePattern":"unsupported leonardo\\.ai model: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/media/index.ts","lineNumber":2192,"sourceCode":"  if (!credentials.apiKey) {\n    throw new Error(\n      'no Leonardo.ai API key — configure it in Settings or set LEONARDO_API_KEY',\n    );\n  }\n  const baseUrl = (credentials.baseUrl || 'https://cloud.leonardo.ai/api/rest/v1').replace(/\\/$/, '');\n  \n  // Map model IDs to Leonardo.ai platform model IDs\n  const modelMap: Record<string, string> = {\n    'leonardo-phoenix': '6b645e3a-d64f-4341-a6d8-7a3690fbf042',  // Phoenix\n    'leonardo-kino-xl': 'aa77f04e-3eec-4034-9c07-d0f619684628',  // Kino XL\n    'leonardo-flux-dev': 'b2614463-296c-462a-9586-aafdb8f00e36', // FLUX.1 [dev]\n    'leonardo-flux-schnell': '1dd50843-d653-4516-a8e3-f0238ee453ff', // FLUX.1 [schnell]\n    'leonardo-anime-pastel': '1e60896f-3c26-4296-8ecc-53e2afecc132', // Anime Pastel Dream\n  };\n  \n  const platformModelId = modelMap[ctx.model];\n  if (!platformModelId) {\n    throw new Error(`unsupported leonardo.ai model: ${ctx.model}`);\n  }\n  \n  // Map aspect ratios to Leonardo.ai dimensions\n  const aspectMap: Record<string, { width: number; height: number }> = {\n    '1:1': { width: 1024, height: 1024 },\n    '16:9': { width: 1344, height: 768 },\n    '9:16': { width: 768, height: 1344 },\n    '4:3': { width: 1152, height: 896 },\n    '3:4': { width: 896, height: 1152 },\n  };\n  \n  const size = (ctx.aspect ? aspectMap[ctx.aspect] : undefined) || { width: 1024, height: 1024 };\n  \n  // Submit generation request. Phoenix and the FLUX family require the\n  // `contrast` field per Leonardo's API reference; valid values are\n  // 3 (Low) / 3.5 (Medium) / 4 (High). Default to 3.5 so prompts that\n  // omit a contrast hint fall in the middle of the supported range.\n  const requiresContrast =","sourceCodeStart":2174,"sourceCodeEnd":2210,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/media/index.ts#L2174-L2210","documentation":"Thrown by renderLeonardoImage when ctx.model is not a key in the static modelMap. The map holds four Leonardo platform model IDs (phoenix, kino-xl, flux-dev, flux-schnell, anime-pastel); any other model identifier reaches the `if (!platformModelId)` branch. This guards against pushing an unknown model ID to Leonardo's API which would 400 upstream.","triggerScenarios":"User (or a skill/template) passes a model string not in {'leonardo-phoenix','leonardo-kino-xl','leonardo-flux-dev','leonardo-flux-schnell','leonardo-anime-pastel'} to the Leonardo renderer — e.g. a typo, a deprecated ID, or a model the dispatcher routed incorrectly.","commonSituations":"Typo in a skill prompt or template that names the model; Leonardo renamed/added a model and the user expects the new ID before the map is updated; a legacy project file references an old model alias.","solutions":["Use one of the supported model IDs: leonardo-phoenix, leonardo-kino-xl, leonardo-flux-dev, leonardo-flux-schnell, or leonardo-anime-pastel.","If you need a newly released Leonardo model, extend the modelMap in apps/daemon/src/media/index.ts (around line 2185) and rebuild the daemon.","Check for typos: the prefix is 'leonardo-' (lowercase, hyphen-separated), not 'leonardo_' or 'Leonardo-'.","If invoking through a skill/template, inspect the rendered prompt to confirm which model string it actually sent."],"exampleFix":"// before\nctx.model = 'leonardo-flux' // not in the map → [463]\n\n// after\nctx.model = 'leonardo-flux-dev' // valid map key","handlingStrategy":"validation","validationCode":"// Validate the model id is supported before reaching the renderer.\nconst LEONARDO_SUPPORTED_MODELS = new Set([\n  'leonardo-phoenix',\n  'leonardo-kino-xl',\n  'leonardo-flux-dev',\n  'leonardo-flux-schnell',\n  'leonardo-anime-pastel',\n]);\nfunction assertLeonardoModelSupported(model: string): void {\n  if (!LEONARDO_SUPPORTED_MODELS.has(model)) {\n    throw new Error(\n      `unsupported leonardo.ai model: ${model}. Supported: ${[...LEONARDO_SUPPORTED_MODELS].join(', ')}`,\n    );\n  }\n}","typeGuard":"function isLeonardoSupportedModel(m: string): m is\n  | 'leonardo-phoenix'\n  | 'leonardo-kino-xl'\n  | 'leonardo-flux-dev'\n  | 'leonardo-flux-schnell'\n  | 'leonardo-anime-pastel' {\n  return LEONARDO_SUPPORTED_MODELS.has(m);\n}","tryCatchPattern":null,"preventionTips":["Expose the supported Leonardo model list as a contract type so the UI can offer a picker instead of a free-text field.","When Leonardo releases a new model, add it to the Set AND the modelMap in the same commit, with a release note.","Gate skill/template model references through a lint pass that rejects unknown Leonardo model ids."],"tags":["leonardo","model-selection","validation","configuration"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}