decolua/9router · error · Error

Invalid HuggingFace model ID

Error message

Invalid HuggingFace model ID

What it means

The HuggingFace TTS handler validates the model ID before calling the Inference API endpoint `{baseUrl}/{modelId}`. It throws when `modelId` is missing/empty or contains `..` (a path-traversal guard, since the ID is interpolated directly into the URL path). HuggingFace model IDs are `owner/repo` names, not paths.

Source

Thrown at open-sse/handlers/ttsProviders/genericFormats.js:44

  });
  if (!res.ok) await throwUpstreamError(res);
  return responseToBase64(res, "mp3");
}

// Nvidia NIM: POST { input: { text }, voice, model } → binary
async function nvidia({ baseUrl, apiKey, text, modelId, voiceId }) {
  const res = await fetch(baseUrl, {
    method: "POST",
    headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` },
    body: JSON.stringify({ input: { text }, voice: voiceId || "default", model: modelId }),
  });
  if (!res.ok) await throwUpstreamError(res);
  return responseToBase64(res, "wav");
}

// HuggingFace: POST {baseUrl}/{modelId} { inputs: text } → binary
async function huggingface({ baseUrl, apiKey, text, modelId }) {
  if (!modelId || modelId.includes("..")) throw new Error("Invalid HuggingFace model ID");
  const res = await fetch(`${baseUrl}/${modelId}`, {
    method: "POST",
    headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` },
    body: JSON.stringify({ inputs: text }),
  });
  if (!res.ok) await throwUpstreamError(res);
  return responseToBase64(res, "wav");
}

// Fish Audio: model travels in an HTTP header, the voice is a reference_id, returns binary
async function fishAudio({ baseUrl, apiKey, text, modelId, voiceId }) {
  const res = await fetch(baseUrl, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${apiKey}`,
      "model": modelId || "s2.1-pro-free",
    },

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Pass a valid HuggingFace model ID in `org/model` form, e.g. `espnet/kan-bayashi_ljspeech_vits`
  2. Ensure the provider has tts entries in open-sse/config/providerModels.js so a defaultModel is derived
  3. Send the model as `model` in the request (or `modelId`), not a full URL; strip any `..` segments
  4. Check the resulting request: baseUrl must be the Inference API root, with the model ID appended as path

Example fix

// before
await tts({ provider: 'huggingface', text: 'hi' }); // no model
// after
await tts({ provider: 'huggingface', text: 'hi', model: 'facebook/mms-tts-eng' });
Defensive patterns

Strategy: validation

Validate before calling

function isValidHfModelId(id){ return typeof id === 'string' && /^[\w.-]+\/[\w.-]+$/.test(id) && !id.includes('..'); }
if (!isValidHfModelId(model)) throw new Error('model must be org/repo HuggingFace ID');

Type guard

const isHfModelId = (v) => typeof v === 'string' && v.length > 0 && !v.includes('..') && v.includes('/');

Try / catch

try { await tts({ provider:'huggingface', text, model }); } catch (e) { if (e.message === 'Invalid HuggingFace model ID') { /* fix model config */ } else throw e; }

Prevention

When it happens

Trigger: Calling synthesize with a provider whose ttsConfig format resolves to the huggingface handler while `modelId` is empty (no tts model in PROVIDER_MODELS for the provider, or `model` param absent and no default) or a model string containing `..` such as `../../api/models`.

Common situations: Provider registry missing tts model entries so defaultModel resolves to empty string; user passes a full URL instead of an `org/model` ID; a malicious or malformed model string containing path separators/dots.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/7f0d113eea6f9da2. Report an issue: GitHub.