moeru-ai/airi · error · Error

${openResult}

Error message

${openResult}

What it means

Thrown by the electronAppOpenUserDataFolder IPC handler. Electron's shell.openPath(path) returns an empty string on success and a non-empty error message string on failure; the handler throws that message verbatim. So the error text is OS-supplied (e.g. 'Failed to open path') rather than a hardcoded constant.

Source

Thrown at apps/stage-tamagotchi/src/main/services/electron/app.ts:18

import type { createContext } from '@moeru/eventa/adapters/electron/main'
import type { BrowserWindow } from 'electron'

import { defineInvokeHandler } from '@moeru/eventa'
import { app, shell } from 'electron'
import { isLinux, isMacOS, isWindows } from 'std-env'

import { electron, electronAppOpenUserDataFolder, electronAppQuit } from '../../../shared/eventa'

export function createAppService(params: { context: ReturnType<typeof createContext>['context'], window: BrowserWindow }) {
  defineInvokeHandler(params.context, electron.app.isMacOS, () => isMacOS)
  defineInvokeHandler(params.context, electron.app.isWindows, () => isWindows)
  defineInvokeHandler(params.context, electron.app.isLinux, () => isLinux)
  defineInvokeHandler(params.context, electronAppOpenUserDataFolder, async () => {
    const path = app.getPath('userData')
    const openResult = await shell.openPath(path)
    if (openResult) {
      throw new Error(openResult)
    }
    return { path }
  })
  defineInvokeHandler(params.context, electronAppQuit, () => app.quit())
}

View on GitHub (pinned to 27111382b4)

Solutions

  1. Ensure app.getPath('userData') exists before calling openPath — mkdir it if missing.
  2. Check OS file associations for directory opening (xdg-open on Linux, Finder on macOS).
  3. On Linux, verify xdg-utils is installed and XDG_CURRENT_DESKTOP is set.
  4. Run the app outside a locked-down sandbox that blocks process spawning.

Example fix

// before
const path = app.getPath('userData')
const openResult = await shell.openPath(path)
if (openResult) {
  throw new Error(openResult)
}

// after
const path = app.getPath('userData')
await fs.promises.mkdir(path, { recursive: true })
const openResult = await shell.openPath(path)
if (openResult) {
  throw new Error(`Could not open user data folder: ${openResult}`)
}
Defensive patterns

Strategy: try-catch

Validate before calling

import { existsSync, mkdirSync } from 'node:fs'
import { app } from 'electron'
function ensureUserDataFolder(): string {
  const path = app.getPath('userData')
  if (!existsSync(path)) mkdirSync(path, { recursive: true })
  return path
}

Try / catch

try {
  await invokeOpenUserDataFolder()
} catch (e) {
  // e.message is OS-supplied; surface to user, suggest manual path
  showError(`Could not open the folder automatically. Open it manually: ${app.getPath('userData')}`)
}

Prevention

When it happens

Trigger: User clicks 'Open User Data Folder' in settings; the userData directory does not exist yet, has been deleted, has restrictive permissions, or no application is registered to open a folder on the OS.

Common situations: First run before userData was created; folder moved/deleted externally; Linux without a file manager handler; permissions locked by another process; sandboxed environment blocking shell.openPath.

Related errors


AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12). Data as JSON: /api/errors/c403663883319b42. Report an issue: GitHub.