CherryHQ/cherry-studio · error · Error

Failed to write OAuth storage: ${error instanceof Error ? er

Error message

Failed to write OAuth storage: ${error instanceof Error ? error.message : String(error)}

What it means

Thrown by `writeStorage()` when the atomic write (write temp file → rename to final path) fails. The method creates the parent directory, writes to a `.tmp` file, then renames atomically. Any failure in mkdir, writeFile, or rename triggers this. The cache is not updated on failure, so the in-memory state stays consistent with the last successful write.

Source

Thrown at src/main/ai/mcp/oauth/storage.ts:66

  private async writeStorage(data: OAuthStorageData): Promise<void> {
    try {
      // Ensure directory exists
      await fs.mkdir(path.dirname(this.filePath), { recursive: true })

      // Update timestamp
      data.lastUpdated = Date.now()

      // Write file atomically
      const tempPath = `${this.filePath}.tmp`
      await fs.writeFile(tempPath, JSON.stringify(data, null, 2))
      await fs.rename(tempPath, this.filePath)

      // Update cache
      this.cache = data
    } catch (error) {
      logger.error('Error writing OAuth storage:', error as Error)
      throw new Error(`Failed to write OAuth storage: ${error instanceof Error ? error.message : String(error)}`)
    }
  }

  async getClientInformation(): Promise<OAuthClientInformation | undefined> {
    const data = await this.readStorage()
    return data.clientInfo
  }

  async saveClientInformation(info: OAuthClientInformationMixed | undefined): Promise<void> {
    const data = await this.readStorage()
    await this.writeStorage({
      ...data,
      clientInfo: info
    })
  }

  async getTokens(): Promise<OAuthTokens | undefined> {
    const data = await this.readStorage()

View on GitHub (pinned to 726446b54c)

Solutions

  1. Check available disk space on the volume containing the MCP config directory
  2. Verify write permissions on the config directory (usually under userData/mcp/)
  3. If the rename fails due to cross-filesystem, ensure the .tmp file is created in the same directory as the target (which it is — check for symlink interference)
  4. Retry the operation — transient I/O errors may resolve; if persistent, investigate disk health
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await oauthStorage.saveTokens(tokens)
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Failed to write OAuth storage')) {
    // Check disk space and permissions, then retry
    logger.error('OAuth storage write failed', e)
    // Non-fatal: tokens stay in memory, will be retried on next save
  }
  throw e
}

Prevention

When it happens

Trigger: Disk full preventing the temp file write; permission denied on the config directory; the rename fails across filesystems (temp and target on different mounts); the directory was deleted between mkdir and writeFile; disk I/O hardware error.

Common situations: Disk space exhausted; config directory permissions changed since app start; running from a read-only filesystem; antivirus intercepting the rename on Windows; the OS temp directory and config directory are on different volumes making rename fail.

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/3b0fc838d07dbb14. Report an issue: GitHub.