{"record":{"id":"3f138bde436a136a","repo":"CherryHQ/cherry-studio","slug":"failed-to-read-oauth-storage-error-instanceof-e","errorCode":null,"errorMessage":"Failed to read OAuth storage: ${error instanceof Error ? error.message : String(error)}","messagePattern":"Failed to read OAuth storage: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/mcp/oauth/storage.ts","lineNumber":45,"sourceCode":"    if (this.cache) {\n      return this.cache\n    }\n\n    try {\n      const data = await fs.readFile(this.filePath, 'utf-8')\n      const parsed = JSON.parse(data)\n      const validated = OAuthStorageSchema.parse(parsed)\n      this.cache = validated\n      return validated\n    } catch (error) {\n      if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {\n        // File doesn't exist, return initial state\n        const initial: OAuthStorageData = { lastUpdated: Date.now() }\n        await this.writeStorage(initial)\n        return initial\n      }\n      logger.error('Error reading OAuth storage:', error as Error)\n      throw new Error(`Failed to read OAuth storage: ${error instanceof Error ? error.message : String(error)}`)\n    }\n  }\n\n  private async writeStorage(data: OAuthStorageData): Promise<void> {\n    try {\n      // Ensure directory exists\n      await fs.mkdir(path.dirname(this.filePath), { recursive: true })\n\n      // Update timestamp\n      data.lastUpdated = Date.now()\n\n      // Write file atomically\n      const tempPath = `${this.filePath}.tmp`\n      await fs.writeFile(tempPath, JSON.stringify(data, null, 2))\n      await fs.rename(tempPath, this.filePath)\n\n      // Update cache\n      this.cache = data","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/oauth/storage.ts#L27-L63","documentation":"Thrown by `readStorage()` in the OAuth JSON file storage when reading or parsing the OAuth state file fails with an error other than ENOENT (file-not-found, which is handled gracefully by creating initial state). The file is expected to be valid JSON conforming to OAuthStorageSchema; corruption, schema mismatch, or permission errors trigger this.","triggerScenarios":"The OAuth JSON file (`{serverUrlHash}_oauth.json`) exists but contains invalid JSON, fails Zod schema validation (OAuthStorageSchema.parse), has a permission issue preventing read access, or experiences a disk I/O error.","commonSituations":"File was partially written (crash during write — the atomic rename should prevent this but a hard crash could leave .tmp); file was manually edited and corrupted; file permissions changed; schema changed in an app update and old files don't validate; antivirus locking the file on Windows.","solutions":["Delete or rename the corrupted OAuth JSON file (located in the MCP config directory as `{hash}_oauth.json`) — the runtime will recreate it with initial state on next read","Check file permissions — the Electron app process must have read access","If schema migration is needed, clear all OAuth files and re-authenticate","On Windows, check if antivirus or another process is locking the file"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const tokens = await oauthStorage.getTokens()\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Failed to read OAuth storage')) {\n    // File is corrupted — delete it so next read recreates initial state\n    await fs.unlink(oauthFilePath).catch(() => {})\n    // Restart OAuth flow from scratch\n    return restartOAuthFlow()\n  }\n  throw e\n}","preventionTips":["Never manually edit OAuth JSON files","Handle read failures by deleting the corrupted file and re-authenticating","Monitor disk health — recurring storage corruption may indicate hardware failure"],"tags":["mcp","oauth","storage","file-io","corruption"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}