stablyai/orca · warning · Error

No Claude credentials found in ${resolvedDir}. Run `claude l

Error message

No Claude credentials found in ${resolvedDir}. Run `claude login` into this directory first.

What it means

Thrown by captureFromExistingConfigDir() on non-macOS platforms when the resolved configDir does not contain a .credentials.json file. On Linux/Windows Claude stores OAuth credentials as plaintext .credentials.json, so its absence means the directory was never authenticated via `claude login`. macOS is exempt because credentials live in the Keychain.

Source

Thrown at src/main/claude-accounts/service.ts:218

  // Why: capture credentials from a CLAUDE_CONFIG_DIR the caller already
  // authenticated (e.g. a temp dir the CLI ran `claude login` into), mirroring
  // runClaudeLoginAndCapture's capture step but without spawning the interactive
  // login. On Linux/Windows the credentials live in a plaintext `.credentials.json`.
  private async captureFromExistingConfigDir(
    configDir: string,
    previousLegacyCredentialsSha256?: string | null
  ): Promise<CapturedClaudeAuth> {
    const trimmed = configDir.trim()
    if (!trimmed) {
      throw new Error('A Claude config directory path is required.')
    }
    const resolvedDir = resolve(trimmed)
    // Why: macOS keeps Claude credentials in the Keychain rather than a file, so
    // only require `.credentials.json` off-darwin; captureAuthFromConfigDir reads
    // the scoped Keychain item on macOS.
    if (process.platform !== 'darwin' && !existsSync(join(resolvedDir, '.credentials.json'))) {
      throw new Error(
        `No Claude credentials found in ${resolvedDir}. Run \`claude login\` into this directory first.`
      )
    }
    // Why: `allowFailure` covers a non-zero exit but not a spawn error, and unlike
    // the GUI flow nothing has run `claude` in this process yet — a daemon started
    // with a minimal PATH (launchd/systemd) would hard-fail an add the user already
    // signed in for. Identity still resolves from the config dir's oauthAccount.
    let status = ''
    try {
      status = await this.runClaudeCommand(
        ['auth', 'status', '--json'],
        { windowsPath: resolvedDir, linuxPath: null, wslDistro: null },
        STATUS_TIMEOUT_MS,
        { allowFailure: true }
      )
    } catch (error) {
      console.warn('[claude-accounts] Could not read `claude auth status`:', error)
    }

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Run `claude login` with CLAUDE_CONFIG_DIR set to the exact directory you pass to captureFromExistingConfigDir.
  2. Verify fs.existsSync(join(dir, '.credentials.json')) before calling.
  3. Confirm the directory path is the one the CLI actually used (check for .claude.json / .config.json siblings).
  4. On macOS, remember credentials live in the Keychain, not the file — do not require .credentials.json there.
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync, join } from 'node:path'

if (process.platform !== 'darwin' && !existsSync(join(resolvedDir, '.credentials.json'))) {
  throw new Error(`No credentials in ${resolvedDir}. Run 'claude login' there first.`)
}

Prevention

When it happens

Trigger: On Linux/Windows, calling captureFromExistingConfigDir with a dir where `claude login` was never run, or pointing at the wrong directory. The .credentials.json file was deleted or never created.

Common situations: User selects a fresh/empty temp dir instead of the one they logged into. Path points at the parent of the actual config dir. The CLI wrote credentials to a different CLAUDE_CONFIG_DIR than the one supplied. The login failed silently and left no credentials.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/4a8362dab50bd257. Report an issue: GitHub.