janhq/jan · warning · Error
Model ${modelId} does not exist
Error message
Model ${modelId} does not exist What it means
Thrown by delete() when the target folder's model.yml is absent. delete() resolves provider/models/<modelId>/model.yml and refuses to proceed if it does not exist, because without the config it cannot know the model_path to clean up weights. This guards against deleting arbitrary/empty folders.
Source
Thrown at extensions/mlx-extension/src/index.ts:512
throw new Error(error.message)
}
}
}
} finally {
reader.releaseLock()
}
}
override async delete(modelId: string): Promise<void> {
const modelDir = await joinPath([
await this.getProviderPath(),
'models',
modelId,
])
const modelConfigPath = await joinPath([modelDir, 'model.yml'])
if (!(await fs.existsSync(modelConfigPath))) {
throw new Error(`Model ${modelId} does not exist`)
}
const modelConfig = await invoke<ModelConfig>('read_yaml', {
path: modelConfigPath,
})
// Check if model_path is a relative path within mlx folder
if (!isAbsoluteModelPath(modelConfig.model_path)) {
// Model file is at {janDataFolder}/{model_path}
// Delete the parent folder containing the actual model file
const janDataFolderPath = await getJanDataFolderPath()
const modelPath = await joinPath([
janDataFolderPath,
modelConfig.model_path,
])
const parentDir = modelPath.substring(0, modelPath.lastIndexOf('/'))
// Only delete if it's different from modelDir (i.e., not the same folder)
if (parentDir !== modelDir) {View on GitHub (pinned to fad3f12a14)
Solutions
- Refresh the model list before offering delete so it reflects actual disk state.
- If weights remain without model.yml, locate the model file under the jan data folder and remove it manually, then clear the list entry.
- Guard delete() callers with a list()/exists check and no-op if absent.
- Verify modelId casing/format matches the imported id.
Example fix
// before
await engine.delete(modelId)
// after
const cfg = await joinPath([await engine.getProviderPath(), 'models', modelId, 'model.yml'])
if (!(await fs.existsSync(cfg))) {
logger.warn(`Model ${modelId} already gone; nothing to delete`)
return
}
await engine.delete(modelId) Defensive patterns
Strategy: validation
Validate before calling
async function modelInstalled(providerPath: string, modelId: string): Promise<boolean> {
const p = await joinPath([providerPath, 'models', modelId, 'model.yml'])
return fs.existsSync(p)
}
if (!(await modelInstalled(await engine.getProviderPath(), modelId))) {
logger.warn(`Model ${modelId} not present; skipping delete`)
return
} Try / catch
try {
await engine.delete(modelId)
} catch (e) {
if (/does not exist/.test(String(e))) return // already gone
throw e
} Prevention
- Refresh engine.list() before offering delete.
- Make delete idempotent in UI (no-op if already gone).
- Clear stale list entries when a folder is removed out-of-band.
When it happens
Trigger: Calling delete() on a modelId that was never imported, was already deleted, or whose model.yml was removed manually while weights remain; a modelId with wrong casing/separators that doesn't resolve to the real folder.
Common situations: UI delete action fired twice (second finds it gone); partial delete earlier removed model.yml but not the folder; user manually cleaned model.yml; stale model list shows an id whose folder is gone.
Related errors
- Model with ID ${model.id} already exists
- Model ${modelId} does not exist
- Model already loaded!
- No active MLX session found for model: ${modelId}
- No active MLX session found for model: ${opts.model}
AI-assisted analysis of janhq/jan@fad3f12a14 (2026-08-12).
Data as JSON: /api/errors/739f5f0253ce6eb3.
Report an issue: GitHub.