janhq/jan · warning · Error
Model with ID ${model.id} already exists
Error message
Model with ID ${model.id} already exists What it means
Thrown by update() when renaming a model: the destination folder provider/models/<model.id> already exists. update() moves the model folder from modelId to model.id and rewrites model_path; it refuses to clobber an existing model. The check is a pure filesystem existence test.
Source
Thrown at extensions/mlx-extension/src/index.ts:558
modelId: string,
model: Partial<modelInfo>
): Promise<void> {
// Delegate to the same logic as llamacpp since they share the model dir
const modelFolderPath = await joinPath([
await this.getProviderPath(),
'models',
modelId,
])
const modelConfig = await invoke<ModelConfig>('read_yaml', {
path: await joinPath([modelFolderPath, 'model.yml']),
})
const newFolderPath = await joinPath([
await this.getProviderPath(),
'models',
model.id,
])
if (await fs.existsSync(newFolderPath)) {
throw new Error(`Model with ID ${model.id} already exists`)
}
const newModelConfigPath = await joinPath([newFolderPath, 'model.yml'])
await fs.mv(modelFolderPath, newFolderPath).then(() =>
invoke('write_yaml', {
data: {
...modelConfig,
model_path: modelConfig?.model_path?.replace(
`mlx/models/${modelId}`,
`mlx/models/${model.id}`
),
},
savePath: newModelConfigPath,
})
)
}
override async import(modelId: string, opts: ImportOptions): Promise<void> {
if (!isValidModelId(modelId))View on GitHub (pinned to fad3f12a14)
Solutions
- Choose a new model.id that does not match any existing entry in list().
- Delete or rename the conflicting existing model first.
- If the destination folder is stale leftover (no model.yml), remove it manually then retry.
- On case-insensitive filesystems, pick an id that differs by more than case.
Example fix
// before
await engine.update(modelId, { id: newId })
// after
const dest = await joinPath([await engine.getProviderPath(), 'models', newId])
if (await fs.existsSync(dest)) {
throw new Error(`Name '${newId}' is taken; pick another`)
}
await engine.update(modelId, { id: newId }) Defensive patterns
Strategy: validation
Validate before calling
async function targetNameFree(providerPath: string, newId: string): Promise<boolean> {
return !(await fs.existsSync(await joinPath([providerPath, 'models', newId])))
}
if (!(await targetNameFree(await engine.getProviderPath(), model.id))) {
throw new Error(`Name '${model.id}' already taken`)
} Try / catch
try {
await engine.update(modelId, { id: newId })
} catch (e) {
if (/already exists/.test(String(e))) {
model.id = `${newId}-2` // pick alternate and retry
await engine.update(modelId, { id: model.id })
} else throw e
} Prevention
- Check list() for id collisions before renaming.
- Delete stale leftover destination folders before retry.
- On case-insensitive filesystems, differ by more than case.
When it happens
Trigger: Calling update() to rename a model to an id that is already taken; a previous failed update left the destination folder behind; two models with ids differing only by casing on a case-insensitive filesystem.
Common situations: User picks a new name colliding with another installed model; rename target equals the source (no-op rename); leftover folder from an interrupted prior rename/import.
Related errors
- Model ${modelId} does not exist
- Model with ID ${model.id} already exists
- 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/9132b8c393007fc9.
Report an issue: GitHub.