{"record":{"id":"7f0d113eea6f9da2","repo":"decolua/9router","slug":"invalid-huggingface-model-id","errorCode":null,"errorMessage":"Invalid HuggingFace model ID","messagePattern":"Invalid HuggingFace model ID","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"open-sse/handlers/ttsProviders/genericFormats.js","lineNumber":44,"sourceCode":"  });\n  if (!res.ok) await throwUpstreamError(res);\n  return responseToBase64(res, \"mp3\");\n}\n\n// Nvidia NIM: POST { input: { text }, voice, model } → binary\nasync function nvidia({ baseUrl, apiKey, text, modelId, voiceId }) {\n  const res = await fetch(baseUrl, {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application/json\", \"Authorization\": `Bearer ${apiKey}` },\n    body: JSON.stringify({ input: { text }, voice: voiceId || \"default\", model: modelId }),\n  });\n  if (!res.ok) await throwUpstreamError(res);\n  return responseToBase64(res, \"wav\");\n}\n\n// HuggingFace: POST {baseUrl}/{modelId} { inputs: text } → binary\nasync function huggingface({ baseUrl, apiKey, text, modelId }) {\n  if (!modelId || modelId.includes(\"..\")) throw new Error(\"Invalid HuggingFace model ID\");\n  const res = await fetch(`${baseUrl}/${modelId}`, {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application/json\", \"Authorization\": `Bearer ${apiKey}` },\n    body: JSON.stringify({ inputs: text }),\n  });\n  if (!res.ok) await throwUpstreamError(res);\n  return responseToBase64(res, \"wav\");\n}\n\n// Fish Audio: model travels in an HTTP header, the voice is a reference_id, returns binary\nasync function fishAudio({ baseUrl, apiKey, text, modelId, voiceId }) {\n  const res = await fetch(baseUrl, {\n    method: \"POST\",\n    headers: {\n      \"Content-Type\": \"application/json\",\n      \"Authorization\": `Bearer ${apiKey}`,\n      \"model\": modelId || \"s2.1-pro-free\",\n    },","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/open-sse/handlers/ttsProviders/genericFormats.js#L26-L62","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","solutions":["Pass a valid HuggingFace model ID in `org/model` form, e.g. `espnet/kan-bayashi_ljspeech_vits`","Ensure the provider has tts entries in open-sse/config/providerModels.js so a defaultModel is derived","Send the model as `model` in the request (or `modelId`), not a full URL; strip any `..` segments","Check the resulting request: baseUrl must be the Inference API root, with the model ID appended as path"],"exampleFix":"// before\nawait tts({ provider: 'huggingface', text: 'hi' }); // no model\n// after\nawait tts({ provider: 'huggingface', text: 'hi', model: 'facebook/mms-tts-eng' });","handlingStrategy":"validation","validationCode":"function isValidHfModelId(id){ return typeof id === 'string' && /^[\\w.-]+\\/[\\w.-]+$/.test(id) && !id.includes('..'); }\nif (!isValidHfModelId(model)) throw new Error('model must be org/repo HuggingFace ID');","typeGuard":"const isHfModelId = (v) => typeof v === 'string' && v.length > 0 && !v.includes('..') && v.includes('/');","tryCatchPattern":"try { await tts({ provider:'huggingface', text, model }); } catch (e) { if (e.message === 'Invalid HuggingFace model ID') { /* fix model config */ } else throw e; }","preventionTips":["Always pass model in org/repo form; never a URL or bare repo name","Keep tts models populated in providerModels.js so defaults resolve","Sanitize user-supplied model strings against `..` before calling"],"tags":["validation","tts","huggingface","input-validation"],"backgroundTag":"invalid-model-id","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}