nexu-io/open-design · error · Error

Custom Image API model required — configure the provider mod

Error message

Custom Image API model required — configure the provider model in Settings

What it means

Thrown by renderCustomOpenAIImage after baseUrl is set but no wireModel can be resolved. wireModel falls back from credentials.model to ctx.wireModel only when ctx.wireModel is not the sentinel CUSTOM_IMAGE_MODEL_ID ('custom-image'); if both are missing/empty the renderer refuses because body.model would be blank. The custom provider never has a default model name, so the user must supply one.

Source

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

    bytes,
    providerNote: `imagerouter/${wireModel} · ${imageRouterSizeFor(ctx.aspect, 'video')} · ${seconds === 'auto' ? 'auto' : `${seconds}s`} · ${bytes.length} bytes`,
    suggestedExt: '.mp4',
  };
}

async function renderCustomOpenAIImage(ctx: MediaContext, credentials: ProviderConfig): Promise<RenderResult> {
  const baseUrl = (credentials.baseUrl || '').trim();
  if (!baseUrl) {
    throw new Error(
      'Custom Image API base URL required — configure an OpenAI-compatible /v1/images/generations or /v1/images/edits endpoint in Settings',
    );
  }
  const wireModel = (
    credentials.model
    || (ctx.wireModel !== CUSTOM_IMAGE_MODEL_ID ? ctx.wireModel : '')
  ).trim();
  if (!wireModel) {
    throw new Error(
      'Custom Image API model required — configure the provider model in Settings',
    );
  }

  const headers: Record<string, string> = {
    'content-type': 'application/json',
  };
  if (credentials.apiKey) {
    headers.authorization = `Bearer ${credentials.apiKey}`;
  }
  const body: Record<string, unknown> = {
    prompt: ctx.prompt || 'A high-quality reference image.',
    model: wireModel,
    n: 1,
    size: openaiSizeFor('gpt-image-1', ctx.aspect),
  };
  let url = buildOpenAIImageUrl(baseUrl, false);
  if (ctx.imageRef?.dataUrl) {

View on GitHub (pinned to 5be4028344)

Solutions

  1. In Settings -> Media Providers -> Custom Image API, populate the model field with the wire name your gateway expects (e.g. 'flux-pro', 'sd3.5-large').
  2. Pass --model <wire-name> on the CLI if invoking directly so ctx.wireModel is a real name rather than the sentinel.
  3. Save the settings and re-run; the next failure (if any) will be an upstream HTTP error, which means URL+model+key are wired correctly.

Example fix

// before: --model custom-image, no model in Settings
// after: set --model to the wire name
od media generate --surface image --model custom-image --prompt "..." \
  # plus configure model=flux-pro in Settings -> Media Providers -> Custom Image API
Defensive patterns

Strategy: validation

Validate before calling

const CUSTOM_IMAGE_MODEL_ID = 'custom-image';
function resolveCustomWireModel(creds: {model?: string}, ctxWireModel: string): string {
  const m = (creds.model || (ctxWireModel !== CUSTOM_IMAGE_MODEL_ID ? ctxWireModel : '')).trim();
  if (!m) throw new Error('Custom Image API model required — configure the provider model in Settings');
  return m;
}

Type guard

function hasCustomWireModel(creds: {model?:string}, ctxWireModel: string): boolean {
  const m = (creds.model || (ctxWireModel !== 'custom-image' ? ctxWireModel : '')).trim();
  return m.length > 0;
}

Prevention

When it happens

Trigger: Custom Image API configured with a baseUrl but model left blank in Settings; alias resolves ctx.wireModel to the 'custom-image' sentinel so it is intentionally discarded.

Common situations: User filled in URL but not the model field; settings form split across tabs and the model field was missed; an alias pointed the catalog id at itself.

Related errors


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