janhq/jan · error

Model already exists

Error message

Model ${modelId} already exists

What it means

The model-creation flow writes model.yml at <providerPath>/models/<modelId>/model.yml. If a config file for that modelId already exists, the extension throws this error instead of silently overwriting an existing registered model.

Solutions

  1. Pick a unique modelId not already present in the models directory
  2. Delete the existing <providerPath>/models/<modelId>/model.yml if that model is obsolete
  3. List existing models first and skip/dedupe before registering
  4. Remove the whole stale model directory if it is a leftover partial import

Example fix

// before
await addModel({ modelId: 'qwen2-7b', ... }) // second call with same id
// after
if (!(await modelExists('qwen2-7b'))) await addModel({ modelId: 'qwen2-7b', ... })
Defensive patterns

Strategy: validation

Validate before calling

const configPath = await joinPath([providerPath, 'models', modelId, 'model.yml'])
if (await fs.existsSync(configPath)) return // skip; already registered

Try / catch

try {
  await addModel({ modelId, ...opts })
} catch (e) {
  if (e.message === `Model ${modelId} already exists`) return existingModel
  throw e
}

Prevention

When it happens

Trigger: Calling the register/add-model method with a modelId whose model.yml already exists on disk under the provider's models directory.

Common situations: Adding the same model twice; retrying a registration that partially succeeded; importing a model that duplicates an existing ID; leftover configs after manual deletion of weights but not configs.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of janhq/jan@7205d770c1 (2026-09-17). Data as JSON: /api/errors/babaa9ca2d7c8bb2. Report an issue: GitHub.

Appendix: source

Thrown at extensions/llamacpp-extension/src/index.ts:1899

      // check for empty parts or path traversal
      const parts = id.split('/')
      return parts.every((s) => s !== '' && s !== '.' && s !== '..')
    }

    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`)

    // this is relative to Jan's data folder
    const modelDir = `${this.providerId}/models/${modelId}`

    // we only use these from opts
    // opts.modelPath: URL to the model file
    // opts.mmprojPath: URL to the mmproj file

    let downloadItems: DownloadItem[] = []

    const maybeDownload = async (path: string, saveName: string) => {
      // if URL, add to downloadItems, and return local path
      if (path.startsWith('https://')) {
        const localPath = `${modelDir}/${saveName}`
        downloadItems.push({
          url: path,
          save_path: localPath,
          proxy: await getProxyConfig(),

View on GitHub (pinned to 7205d770c1)