nexu-io/open-design · error · Error

unknown model: ${model}. Pass --model from the registered li

Error message

unknown model: ${model}. Pass --model from the registered list (see /api/media/models), or pass a full fal-ai/* path (e.g. fal-ai/flux/dev) for any Fal model.

What it means

Thrown during model resolution when findMediaModel(model) returns nothing AND the model id matches neither the /^fal-ai\// bypass nor the /^aihubmix-/ bypass. The dispatcher only knows three routes into a renderer: catalogued id, fal-ai/* arbitrary path, or aihubmix-* dynamic id. Anything else is rejected before any provider call.

Source

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

      // endpoint, so synthesize a def on the fly — aihubmixWireModel() strips
      // the `aihubmix-` prefix to the real wire name inside the renderer.
      isCatalogBypass = true;
      def = {
        id: model,
        label: model,
        hint: 'AIHubMix',
        provider: 'aihubmix',
        caps:
          surface === 'image'
            ? ['t2i', 'i2i']
            : surface === 'video'
              ? ['t2v', 'i2v']
              : surface === 'audio'
                ? ['tts']
                : [],
      };
    } else {
      throw new Error(
        `unknown model: ${model}. Pass --model from the registered list (see /api/media/models), ` +
        `or pass a full fal-ai/* path (e.g. fal-ai/flux/dev) for any Fal model.`,
      );
    }
  }
  // Reject cross-surface combinations for catalogued models.
  const resolvedAudioKind =
    surface === 'audio' ? audioKind || 'music' : undefined;
  if (!isFalCustomPath && !isCatalogBypass) {
    const allowed = modelsForSurface(surface, resolvedAudioKind);
    if (!allowed.some((m) => m.id === def.id)) {
      const ids = allowed.map((m) => m.id).join(', ');
      const where =
        surface === 'audio' ? `audio · ${resolvedAudioKind}` : surface;
      throw new Error(
        `model "${model}" is not registered for surface "${where}". Allowed: ${ids}.`,
      );
    }

View on GitHub (pinned to 5be4028344)

Solutions

  1. List registered ids via GET /api/media/models (or od media models --json) and re-run with a valid id.
  2. If the target is a Fal model not yet in the catalog, pass the full path as --model fal-ai/<name> (e.g. fal-ai/flux/dev).
  3. If the target is an AIHubMix model discovered live, prefix the wire name with aihubmix-.
  4. Check media-config.json / OD_MEDIA_MODEL_ALIASES if you expected an alias to resolve the id.

Example fix

// before
od media generate --surface image --model flux --prompt "..."
// after
od media generate --surface image --model fal-ai/flux/dev --prompt "..."
Defensive patterns

Strategy: validation

Validate before calling

async function resolveModelId(requested: string): Promise<string> {
  const known = await fetchRegisteredModelIds(); // GET /api/media/models
  if (known.includes(requested)) return requested;
  if (/^fal-ai\//.test(requested) || /^aihubmix-/.test(requested)) return requested;
  throw new Error(`unknown model: ${requested}. Use an id from /api/media/models or a fal-ai/* path.`);
}

Type guard

function isCatalogOrBypassModel(model: string, registeredIds: string[]): boolean {
  return registeredIds.includes(model) || /^fal-ai\//.test(model) || /^aihubmix-/.test(model);
}

Prevention

When it happens

Trigger: Passing --model with a typo, a deprecated id, a provider-namespaced id from another tool (e.g. 'openai/dall-e-3'), or a bare name like 'flux' instead of the full 'fal-ai/flux/dev'. Also hit when a custom-aliased id was expected but no alias is configured.

Common situations: User copies a model name from a different UI; an agent hallucinates a model id from training data; catalog was updated and an old id was removed; user expects any string to work because 'fal supports everything'.

Related errors


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