janhq/jan · critical · Error

Not a supported backend archive! Missing llama-server binary

Error message

Not a supported backend archive! Missing llama-server binary.

What it means

After decompression succeeds, the extension looks for the llama-server binary at the expected build/bin/ path. If not found there, findLlamaServerDir searches the extracted tree. If that search also returns null (no llama-server anywhere), the backend directory is removed and this error is thrown.

Source

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

      await invoke('decompress', { path: path, outputDir: backendDir })
    } catch (e) {
      logger.error(`Failed to install: ${String(e)}`)
      throw new Error(`Failed to decompress archive: ${String(e)}`)
    }

    const serverName =
      platformName === 'win' ? 'llama-server.exe' : 'llama-server'
    const expectedBinDir = await joinPath([backendDir, 'build', 'bin'])
    const expectedBinPath = await joinPath([expectedBinDir, serverName])

    // Normalize varying archive layouts to `build/bin/`: Jan tarballs already
    // ship it; upstream Linux tarballs nest under `llama-bXXXX/`; upstream
    // Windows zips are flat with the binary + DLLs at the root.
    if (!(await fs.existsSync(expectedBinPath))) {
      const foundDir = await findLlamaServerDir(backendDir, serverName)
      if (!foundDir) {
        await fs.rm(backendDir)
        throw new Error(
          'Not a supported backend archive! Missing llama-server binary.'
        )
      }
      if (foundDir !== expectedBinDir) {
        const staging = `${backendDir}.staging`
        try {
          // Move the binary's dir into build/bin in one rename to keep relative
          // symlinks intact (libggml.so → .so.0 → .so.0.10.0). A flat-root
          // archive can't rename into its own subtree, so stage to a sibling.
          if (foundDir === backendDir) {
            await fs.mv(backendDir, staging)
            await fs.mkdir(await joinPath([backendDir, 'build']))
            await fs.mv(staging, expectedBinDir)
          } else {
            await fs.mkdir(await joinPath([backendDir, 'build']))
            await fs.mv(foundDir, expectedBinDir)
          }
        } catch (e) {

View on GitHub (pinned to fad3f12a14)

Solutions

  1. Use an archive that contains the llama-server binary (the binary release, not the source tarball).
  2. If installing CUDA runtime DLLs, use installCudaRuntime instead of the backend installer.
  3. Verify the archive contents manually (unzip/tar -tf) to confirm llama-server is present.
Defensive patterns

Strategy: validation

Validate before calling

// After decompression, check for the binary before the extension does:
import fs from 'node:fs'
import path from 'node:path'

function findBinary(dir: string, serverName: string): string | null {
  const entries = fs.readdirSync(dir, { withFileTypes: true })
  for (const entry of entries) {
    const full = path.join(dir, entry.name)
    if (entry.isDirectory()) {
      const found = findBinary(full, serverName)
      if (found) return found
    } else if (entry.name === serverName) {
      return full
    }
  }
  return null
}

const found = findBinary(backendDir, serverName)
if (!found) throw new Error('Archive has no llama-server; use a binary release')

Prevention

When it happens

Trigger: The archive extracted successfully but contains no llama-server (or llama-server.exe on Windows) binary anywhere in its tree. The archive is either not a llama.cpp backend archive or is an incomplete/partial release.

Common situations: User installed a source-code archive instead of a binary release; the archive is a runtime-only package (e.g. CUDA DLLs) mistakenly passed to the backend installer; upstream release was published without the server binary.

Related errors


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