janhq/jan · error · Error
Model ${modelId} already exists
Error message
Model ${modelId} already exists What it means
Thrown by MlxExtension.import() when a model.yml already exists at <providerPath>/models/<modelId>/model.yml. The extension refuses to clobber an existing model registration, so import is treated as create-only, not upsert. The check runs after modelId format validation but before any download or folder copy.
Source
Thrown at extensions/mlx-extension/src/index.ts:588
savePath: newModelConfigPath,
})
)
}
override async import(modelId: string, opts: ImportOptions): Promise<void> {
if (!isValidModelId(modelId))
throw new Error(
`Invalid modelId: ${modelId}. Only alphanumeric and / _ - . characters are allowed.`
)
const configPath = await joinPath([
await this.getProviderPath(),
'models',
modelId,
'model.yml',
])
if (await fs.existsSync(configPath))
throw new Error(`Model ${modelId} already exists`)
const sourcePath = opts.modelPath
if (sourcePath.startsWith('https://')) {
// Download from URL to mlx models folder
const janDataFolderPath = await getJanDataFolderPath()
const modelDir = await joinPath([
janDataFolderPath,
'mlx',
'models',
modelId,
])
const localPath = await joinPath([modelDir, 'model.safetensors'])
const downloadManager = window.core.extensionManager.getByName(
'@janhq/download-extension'
)
View on GitHub (pinned to fad3f12a14)
Solutions
- Delete or rename the existing folder <JanData>/mlx/models/<modelId> (and its model.yml) before re-importing.
- Use a different modelId for the new import to avoid the collision.
- Call a list/get API (or fs.existsSync on the config path) first and treat an existing model as an update, not an error.
- If the previous import failed mid-way, clean up the partial model.yml it left behind.
Example fix
// before
await mlx.import(modelId, opts) // throws if model.yml exists
// after
const exists = await fs.existsSync(configPath)
if (exists) {
await fs.rm(modelDir, { recursive: true, force: true })
}
await mlx.import(modelId, opts) Defensive patterns
Strategy: validation
Validate before calling
import { fs, joinPath } from '@janhq/janope'
async function modelExists(modelId: string): Promise<boolean> {
const providerPath = await mlx.getProviderPath()
const configPath = await joinPath([providerPath, 'models', modelId, 'model.yml'])
return fs.existsSync(configPath)
}
if (await modelExists(modelId)) {
// delete first, or pick a new id, or treat as update
} Try / catch
try {
await mlx.import(modelId, opts)
} catch (e) {
if (e instanceof Error && e.message.endsWith('already exists')) {
// idempotent: model already registered
} else throw e
} Prevention
- Track which modelIds have been imported so re-imports are intentional.
- Clean up the model folder before re-importing to avoid stale model.yml.
- Use a unique modelId per source to avoid collisions.
When it happens
Trigger: Calling import(modelId, opts) a second time with the same modelId; calling import after a previous import partially succeeded and left model.yml behind; importing a modelId that collides with a model registered through a different provider path.
Common situations: Re-running an import after a download error was already recovered; user re-clicking 'Import' in the UI for the same model; CI re-running a setup script that imports MLX models; modelId collision between a HuggingFace-style ID and a local alias.
Related errors
- Folder not found: ${sourcePath}
- Model ${modelId} already exists
- File not found: ${path}
- Model ${modelId} does not exist
- Model with ID ${model.id} already exists
AI-assisted analysis of janhq/jan@fad3f12a14 (2026-08-12).
Data as JSON: /api/errors/f2235e03a624bdfb.
Report an issue: GitHub.