janhq/jan · error · Error

Model ${modelId} does not exist

Error message

Model ${modelId} does not exist

What it means

Thrown by delete() when <provider>/models/<modelId>/model.yml does not exist. model.yml is the canonical 'this model is installed' marker; absence means the model was never imported, was already deleted, or its folder is corrupted (only partial files remain). delete refuses to proceed (and notably does NOT call fs.rm) to avoid silently removing an unrelated directory.

Source

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

          errorData
        )}`
      )
    }

    const completionResponse = (await response.json()) as chatCompletion

    return completionResponse
  }

  override async delete(modelId: string): Promise<void> {
    const modelDir = await joinPath([
      await this.getProviderPath(),
      'models',
      modelId,
    ])

    if (!(await fs.existsSync(await joinPath([modelDir, 'model.yml'])))) {
      throw new Error(`Model ${modelId} does not exist`)
    }

    await fs.rm(modelDir)

    try {
      await this.refreshRouterPreset()
    } catch (e) {
      logger.warn(`Router refresh after delete(${modelId}) failed:`, e)
    }
  }

  override async getLoadedModels(): Promise<string[]> {
    try {
      let models: string[] = await invoke<string[]>(
        'plugin:llamacpp|get_loaded_models'
      )
      return models
    } catch (e) {

View on GitHub (pinned to fad3f12a14)

Solutions

  1. Refresh the model list before offering delete; if the id is gone, drop it from the UI.
  2. Treat 'does not exist' as success if your goal is simply 'ensure the model is gone'.
  3. Verify the modelId matches the id shown at import time (case, slashes).
  4. If model.yml is missing but the folder has weight files, manually remove the orphan folder.

Example fix

// before
await provider.delete('qwen') // throws if already gone
// after
try { await provider.delete('qwen') }
catch (e) { if (!/does not exist/.test(String(e))) throw e; /* already gone - fine */ }
// or pre-check:
const yml = await joinPath([await provider.getProviderPath(), 'models', 'qwen', 'model.yml'])
if (await fs.existsSync(yml)) await provider.delete('qwen')
Defensive patterns

Strategy: validation

Validate before calling

// Confirm model.yml exists before calling delete
const yml = await joinPath([await provider.getProviderPath(), 'models', modelId, 'model.yml'])
if (!(await fs.existsSync(yml))) {
  // already gone, or never imported - treat as no-op
  return
}
await provider.delete(modelId)

Type guard

async function modelIsInstalled(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.delete(modelId) }
catch (e) {
  if (/does not exist/.test(String(e))) return // already gone - fine
  throw e
}

Prevention

When it happens

Trigger: Calling delete on an id that was never imported; double-delete (UI fired the action twice); model folder partially cleaned by a previous failed delete leaving no model.yml; user hand-deleted model.yml but left the folder; wrong id (typo/case).

Common situations: UI list is stale and shows a model already removed from disk. Migrating between data folders leaves dangling list entries. User clicks delete twice quickly. Case-insensitive FS id mismatch.

Related errors


AI-assisted analysis of janhq/jan@fad3f12a14 (2026-08-12). Data as JSON: /api/errors/d53078848ec99dc0. Report an issue: GitHub.