janhq/jan · error · Error
model.yml not found for ${modelId}
Error message
model.yml not found for ${modelId} What it means
Thrown by updateMtpSettings() when <provider>/models/<modelId>/model.yml does not exist. The method patches MTP/speculative-decoding fields onto the existing config and re-writes it; without model.yml there is nothing to read or patch. The same guard exists in updateModelSettings() (line 3958) and is the canonical precondition for any per-model config write.
Source
Thrown at extensions/llamacpp-extension/src/index.ts:3904
}
async updateMtpSettings(
modelId: string,
patch: {
mtp?: boolean
spec_draft_n_max?: number | null
spec_draft_n_min?: number | null
spec_draft_p_min?: number | null
}
): Promise<void> {
const configPath = await joinPath([
await this.getProviderPath(),
'models',
modelId,
'model.yml',
])
if (!(await fs.existsSync(configPath))) {
throw new Error(`model.yml not found for ${modelId}`)
}
const cfg = (await invoke<ModelConfig>('read_yaml', { path: configPath })) as ModelConfig & {
mtp?: boolean
spec_draft_n_max?: number
spec_draft_n_min?: number
spec_draft_p_min?: number
}
if (typeof patch.mtp === 'boolean') cfg.mtp = patch.mtp
const assignNumeric = (
key: 'spec_draft_n_max' | 'spec_draft_n_min' | 'spec_draft_p_min',
value: number | null | undefined
) => {
if (value === null) {
delete cfg[key]
} else if (typeof value === 'number' && Number.isFinite(value)) {
cfg[key] = value
}View on GitHub (pinned to fad3f12a14)
Solutions
- Ensure the model is fully imported (import() resolved, model.yml on disk) before updating MTP settings.
- Pre-check fs.existsSync(configPath) and disable the MTP controls in the UI until it exists.
- If model.yml was lost, re-import the model.
- Verify the modelId casing/spelling matches the imported id.
Example fix
// before
await provider.updateMtpSettings('qwen', { mtp: true }) // throws - not imported yet
// after - gate on import completion
const yml = await joinPath([await provider.getProviderPath(), 'models', 'qwen', 'model.yml'])
if (!(await fs.existsSync(yml))) { throw new Error('model not fully imported yet') }
await provider.updateMtpSettings('qwen', { mtp: true }) Defensive patterns
Strategy: validation
Validate before calling
// Ensure model.yml exists before patching MTP settings
const yml = await joinPath([await provider.getProviderPath(), 'models', modelId, 'model.yml'])
if (!(await fs.existsSync(yml))) {
throw new Error(`Cannot update MTP settings: '${modelId}' is not fully imported (model.yml missing)`)
} Type guard
async function modelConfigExists(provider: { getProviderPath(): Promise<string> }, id: string): Promise<boolean> {
const yml = await joinPath([await provider.getProviderPath(), 'models', id, 'model.yml'])
return fs.existsSync(yml)
} Try / catch
try { await provider.updateMtpSettings(modelId, patch) }
catch (e) {
if (/model\.yml not found/.test(String(e))) { /* disable MTP UI until import finishes */ }
else throw e
} Prevention
- Disable MTP/settings controls in the UI until import() has resolved and model.yml is written.
- Gate any per-model config write on the existence of model.yml at the caller.
- Re-import the model if model.yml was lost.
When it happens
Trigger: Calling updateMtpSettings on an id that was never imported or was deleted; the model folder exists but model.yml is missing (corrupt/partial import); wrong id (typo/case); calling it before import() has finished writing model.yml.
Common situations: UI lets the user open MTP settings for a model still downloading (model.yml not yet written). Migrating models by copying weight files but forgetting model.yml. Race: import failed validation but the UI still shows the row. Case-insensitive FS id mismatch.
Related errors
- Model with ID ${model.id} already exists
- Model ${modelId} already exists
- File not found: ${path}
- Model ${modelId} does not exist
- Invalid modelId: ${modelId}. Only alphanumeric and / _ - . c
AI-assisted analysis of janhq/jan@fad3f12a14 (2026-08-12).
Data as JSON: /api/errors/42a74608cd081351.
Report an issue: GitHub.