usebruno/bruno · error · Error

Export path: ${filePath} is not an existing directory

Error message

Export path: ${filePath} is not an existing directory

What it means

Thrown by 'renderer:export-environment' after the absolute-path check passes but fs.existsSync(filePath) is false or isDirectory(filePath) is false. The handler will not write export files into a non-existent or file (non-directory) path.

Source

Thrown at packages/bruno-electron/src/ipc/collection.js:969

        const fileContent = fs.readFileSync(envFilePath, 'utf8');
        const environment = parseEnvironment(fileContent, { format });
        environment.color = color;
        const updatedContent = stringifyEnvironment(environment, { format });
        await writeFile(envFilePath, updatedContent);
      });
    } catch (error) {
      return Promise.reject(error);
    }
  });

  // Generic environment export handler
  ipcMain.handle('renderer:export-environment', async (event, { environments, environmentType, filePath, exportFormat = 'folder' }) => {
    try {
      if (!filePath || typeof filePath !== 'string' || !path.isAbsolute(filePath)) {
        throw new Error('Export path must be an absolute directory path');
      }
      if (!fs.existsSync(filePath) || !isDirectory(filePath)) {
        throw new Error(`Export path: ${filePath} is not an existing directory`);
      }
      if (environmentType !== 'collection' && environmentType !== 'global') {
        throw new Error(`Unsupported environment type: ${environmentType}`);
      }

      const { app } = require('electron');
      const appVersion = app?.getVersion() || '2.0.0';

      // For single environments and folder exports, include info in each environment
      const environmentWithInfo = (environment) => ({
        name: environment.name,
        variables: environment.variables,
        color: environment.color ?? undefined,
        info: {
          type: 'bruno-environment',
          exportedAt: new Date().toISOString(),
          exportedUsing: `Bruno/v${appVersion}`
        }

View on GitHub (pinned to 9bdd81c7bd)

Solutions

  1. Re-pick the directory via the folder dialog immediately before export.
  2. Validate with fs.statSync(p).isDirectory() on the renderer side through a stat IPC, or surface the error and prompt re-selection.
  3. Confirm the volume/share is mounted before retrying.

Example fix

// before
await window.Ipc.invoke('renderer:export-environment', { environments, environmentType, filePath: staleDir });

// after
const { filePath } = await window.ipc.invoke('main:select-directory');
await window.Ipc.invoke('renderer:export-environment', { environments, environmentType, filePath });
Defensive patterns

Strategy: validation

Validate before calling

const stat = await window.ipc.invoke('main:stat', filePath);
if (!stat || !stat.isDirectory()) {
  throw new Error(`'${filePath}' is not an existing directory`);
}

Type guard

function isExistingDirectory(stat: { isDirectory: () => boolean } | null): boolean {
  return !!stat && typeof stat.isDirectory === 'function' && stat.isDirectory();
}

Try / catch

try {
  await window.Ipc.invoke('renderer:export-environment', payload);
} catch (e) {
  if (String(e?.message).includes('not an existing directory')) {
    payload.filePath = await pickFolder(); await window.Ipc.invoke('renderer:export-environment', payload);
  } else throw e;
}

Prevention

When it happens

Trigger: Passing an absolute path to a file instead of a folder, a path on a removable/unmounted drive, a deleted/moved directory, or a network share that is no longer mounted.

Common situations: User deleted/moved the target folder after picking it, chose a file path in an open-dialog that returns a file, removable media ejected, or SMB/NFS share dropped.

Related errors


AI-assisted analysis of usebruno/bruno@9bdd81c7bd (2026-08-13). Data as JSON: /api/errors/e76a7db633a83143. Report an issue: GitHub.