janhq/jan · error · Error

${String(e)}

Error message

${String(e)}

What it means

Thrown by findSessionByModel() when the underlying Tauri/Rust invoke('plugin:llamacpp|find_session_by_model') rejects. This private helper is called by load() and unload() to query the router's session table; any IPC/plugin-layer failure (plugin not registered, Rust panic, router plugin not initialized, IPC serialization error) is caught, logged, and re-thrown as a plain Error wrapping String(e).

Source

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

          }
        }
      }
    } finally {
      reader.releaseLock()
    }
  }

  private async findSessionByModel(
    modelId: string
  ): Promise<SessionInfo | null> {
    try {
      return await invoke<SessionInfo | null>(
        'plugin:llamacpp|find_session_by_model',
        { modelId }
      )
    } catch (e) {
      logger.error(e)
      throw new Error(String(e))
    }
  }

  private async ensureHealthySession(modelId: string): Promise<SessionInfo> {
    return invoke<SessionInfo>('plugin:llamacpp|ensure_session_ready', {
      modelId,
      isEmbedding: false,
    })
  }

  override async chat(
    opts: chatCompletionRequest,
    abortController?: AbortController
  ): Promise<chatCompletion | AsyncIterable<chatCompletionChunk>> {
    const sessionInfo = await this.ensureHealthySession(opts.model)
    const baseUrl = `http://localhost:${sessionInfo.port}/v1`
    const url = `${baseUrl}/chat/completions`
    const headers = {

View on GitHub (pinned to fad3f12a14)

Solutions

  1. Check logger.error output for the raw rejection value (logged just before the throw).
  2. Restart the app/router so the plugin re-initializes and re-registers its IPC commands.
  3. Ensure the extension (TS) and the plugin (Rust) are from the same release - mismatched IPC command names are the usual cause.
  4. If String(e) is '[object Object]', the catch loses detail; inspect e with util.inspect/JSON.stringify in dev to recover the real cause.

Example fix

// before
const s = await provider.findSessionByModel('qwen') // throws opaque String(e)
// after - improve error shape at the boundary
class IpcError extends Error {
  constructor(public cause: unknown) { super(typeof cause === 'string' ? cause : JSON.stringify(cause)) }
}
// in findSessionByModel catch:
//   throw new IpcError(e)  // preserves object shape for callers
// caller:
try { await provider.load('qwen') }
catch (e) { console.error('plugin ipc failed:', e); /* restart router */ }
Defensive patterns

Strategy: try-catch

Validate before calling

// Caller can't validate plugin internals; best pre-check is router liveness.
if (!(await provider.getRouterInfo())) throw new Error('router not alive - find_session_by_model will fail')

Type guard

// The catch loses detail; improve it at the source instead.
function asMessage(e: unknown): string {
  return e instanceof Error ? e.message : typeof e === 'string' ? e : JSON.stringify(e)
}

Try / catch

try { await provider.load(modelId) }
catch (e) {
  // findSessionByModel wraps; treat plugin-IPC errors as 'restart needed'
  logger.error('plugin ipc failed, restarting router:', e)
  await provider.startRouter()
  await provider.load(modelId)
}

Prevention

When it happens

Trigger: The llamacpp plugin (Rust side) failed to load or is not registered. The router plugin's IPC channel is broken after a crash. The Rust handler panicked on a malformed modelId. Tauri IPC serialization mismatch (struct shape changed across versions). The plugin sidecar process died mid-call.

Common situations: Extension/plugin version skew (TS calls an IPC command the installed Rust plugin does not expose). Router plugin crashed and the IPC layer returns an error object whose String form is '[object Object]' or a JSON blob. Development hot-reload left the plugin in a half-initialized state.

Related errors


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