usebruno/bruno · error · Error

environment: ${envFilePath} does not exist

Error message

environment: ${envFilePath} does not exist

What it means

Thrown by 'renderer:save-environment' when the resolved environment file does not exist. Notable behavior: the handler first ensures the environments directory exists (creating it if needed) but then REQUIRES the environment file itself to already exist — save-environment overwrites, it does not create a new environment file. The subsequent read-then-write is serialized with a file lock to prevent lost updates from concurrent bru.setEnvVar persist calls.

Source

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

      await writeFile(envFilePath, content);
    } catch (error) {
      return Promise.reject(error);
    }
  });

  // save environment
  ipcMain.handle('renderer:save-environment', async (event, collectionPathname, environment) => {
    try {
      const format = getCollectionFormat(collectionPathname);
      const envFilePath = resolveEnvironmentFilePath(collectionPathname, environment.name, format);

      const envDirPath = path.dirname(envFilePath);
      if (!fs.existsSync(envDirPath)) {
        await createDirectory(envDirPath);
      }

      if (!fs.existsSync(envFilePath)) {
        throw new Error(`environment: ${envFilePath} does not exist`);
      }

      // Serialize concurrent saves to the same env file. Without the lock the
      // read-then-write pattern below can interleave: writer A reads pre-A state,
      // writer B reads pre-A state, B writes B-content, A writes A-content —
      // dropping B's update. Rapid scripted `bru.setEnvVar(..., {persist:true})`
      // calls (e.g. across folder-run requests) hit this without serialization.
      await withFileLock(envFilePath, async () => {
        if (envHasSecrets(environment)) {
          environmentSecretsStore.storeEnvSecrets(collectionPathname, environment);
        }

        const content = await stringifyEnvironment(environment, { format });
        const existing = fs.readFileSync(envFilePath, 'utf8');
        if (content === existing) return; // skip write if content unchanged
        await writeFile(envFilePath, content);
      });
    } catch (error) {

View on GitHub (pinned to 9bdd81c7bd)

Solutions

  1. Create the environment first via the create-environment flow, then call save-environment.
  2. Verify envFilePath exists (or that the environment name is in the collection's bruno.json environment list) before saving.
  3. If the environments directory was recreated but files are missing, re-initialize the environment files from the config.
Defensive patterns

Strategy: validation

Validate before calling

const envFile = await window.ipcRenderer.invoke('renderer:resolve-environment-file-path', collectionPathname, environment.name, format);
const exists = await window.ipcRenderer.invoke('renderer:file-exists', envFile);
if (!exists) {
  // create the environment first, then save
}

Try / catch

try {
  await window.ipcRenderer.invoke('renderer:save-environment', collectionPathname, environment);
} catch (e) {
  if (/environment:.+does not exist/.test(e.message)) {
    await window.ipcRenderer.invoke('renderer:create-environment', collectionPathname, environment);
    await window.ipcRenderer.invoke('renderer:save-environment', collectionPathname, environment);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling save-environment for an environment that was never created, was deleted, or whose name is misspelled. Saving 'Local' or another env that has no file yet. Race where another process deletes the env file between resolve and the existence check.

Common situations: UI allows editing an env that has no backing file. A collection imported from elsewhere missing the environments folder files. Name casing mismatch on case-sensitive filesystems.

Related errors


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