usebruno/bruno · error · Error

${request.filename} is not a valid filename

Error message

${request.filename} is not a valid filename

What it means

Thrown by the 'renderer:save-new-request' IPC handler when the filename portion of a new request fails the strict filesystem-name validator (validateName). validateName rejects names containing <>:"/\|?* or control chars, leading space/hyphen, trailing dot/space, Windows reserved device names (CON, PRN, AUX, NUL, COM[0-9], LPT[0-9]), and names longer than 255 chars. The check runs on the base name with the collection format extension (e.g. .bru) stripped, so the extension itself is never the problem.

Source

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

  });

  // new request
  ipcMain.handle('renderer:new-request', async (event, pathname, request) => {
    try {
      if (fs.existsSync(pathname)) {
        throw new Error(`path: ${pathname} already exists`);
      }

      const collectionPath = findCollectionPathByItemPath(pathname);
      if (!collectionPath) {
        throw new Error('Collection not found for the given pathname');
      }
      const format = getCollectionFormat(collectionPath);

      // For the actual filename part, we want to be strict
      const baseFilename = request?.filename?.replace(`.${format}`, '');
      if (!validateName(baseFilename)) {
        throw new Error(`${request.filename} is not a valid filename`);
      }
      validatePathIsInsideCollection(pathname);

      const content = await stringifyRequestViaWorker(request, { format });
      await writeFile(pathname, content);
    } catch (error) {
      return Promise.reject(error);
    }
  });

  // save request
  ipcMain.handle('renderer:save-request', async (event, pathname, request, format) => {
    try {
      if (!fs.existsSync(pathname)) {
        throw new Error(`path: ${pathname} does not exist`);
      }

      validatePathIsInsideCollection(pathname);

View on GitHub (pinned to 9bdd81c7bd)

Solutions

  1. Sanitize request.filename (e.g. strip/replace /[<>:"/\\|?*\x00-\x1F]/ and trim leading spaces/hyphens and trailing dots/spaces) before invoking the IPC.
  2. Verify the basename is not a Windows reserved name (CON, PRN, AUX, NUL, COM1-9, LPT1-9) before sending.
  3. Pass only the filename (not a path) as request.filename; let the caller build the full pathname.
  4. Surface the validator's rules in the UI name input so users cannot submit invalid names.

Example fix

// before
await window.ipcRenderer.invoke('renderer:save-new-request', pathname, { filename: 'GET /users', ... });

// after
const clean = raw.replace(/[<>:"/\\|?*\x00-\x1F]/g, '').trim().replace(/^[\s-]+/, '').replace(/[.\s]+$/, '');
if (/^(CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9])$/i.test(clean)) throw new Error('reserved name');
await window.ipcRenderer.invoke('renderer:save-new-request', pathname, { filename: `${clean}.${format}`, ... });
Defensive patterns

Strategy: validation

Validate before calling

// Replicates bruno-electron validateName (filesystem.js:291)
function isValidRequestFilename(name) {
  if (typeof name !== 'string' || name.length === 0 || name.length > 255) return false;
  if (/^(CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9])$/i.test(name)) return false;
  return /^[^\s\-<>:"/\\|?*\x00-\x1F]/.test(name)
    && /^[^<>:"/\\|?*\x00-\x1F]*$/.test(name)
    && /[^.\s<>:"/\\|?*\x00-\x1F]$/.test(name);
}
// strip the format extension the same way the handler does before validating
const base = request.filename.replace(/\.(bru|yml)$/, '');
if (!isValidRequestFilename(base)) throw new Error('invalid filename');

Type guard

function isCleanFilename(name) {
  return typeof name === 'string'
    && name.length > 0 && name.length <= 255
    && !/^(CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9])$/i.test(name)
    && /^[^\s\-<>:"/\\|?*\x00-\x1F]/.test(name)
    && /^[^<>:"/\\|?*\x00-\x1F]*$/.test(name)
    && /[^.\s<>:"/\\|?*\x00-\x1F]$/.test(name);
}

Try / catch

try {
  await window.ipcRenderer.invoke('renderer:save-new-request', pathname, request);
} catch (e) {
  if (/is not a valid filename/.test(e.message)) {
    // sanitize and retry with a cleaned name, or surface to the user
  } else throw e;
}

Prevention

When it happens

Trigger: Calling ipcMain 'renderer:save-new-request' with request.filename such as 'a/b', 'foo:bar', ' leading', 'trailing.', 'CON', or a name >255 chars. Any path separator or forbidden char in the filename triggers it because validateName is applied after stripping the format extension.

Common situations: A user pastes a request name containing a slash or colon (e.g. copied from a URL like 'GET /users'). Names ending in a dot on Windows. Names that match a DOS device name. A frontend bug that passes the full pathname instead of just the filename into request.filename.

Related errors


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