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
- Sanitize request.filename (e.g. strip/replace /[<>:"/\\|?*\x00-\x1F]/ and trim leading spaces/hyphens and trailing dots/spaces) before invoking the IPC.
- Verify the basename is not a Windows reserved name (CON, PRN, AUX, NUL, COM1-9, LPT1-9) before sending.
- Pass only the filename (not a path) as request.filename; let the caller build the full pathname.
- 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
- Sanitize user-typed request names through the same regex the main process uses before the IPC call.
- Never put path separators in request.filename; build the full pathname on the caller side.
- Block Windows reserved device names (CON, PRN, AUX, NUL, COM1-9, LPT1-9) in the UI input.
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
- A file with the name "${finalFilename}" already exists in th
- path: ${pathname} does not exist
- Source path: ${sourcePathname} does not exist
- Target directory: ${targetDirname} does not exist
- environment: ${newEnvFilePath} already exists
AI-assisted analysis of usebruno/bruno@9bdd81c7bd (2026-08-13).
Data as JSON: /api/errors/35b669a5eb7d7ecf.
Report an issue: GitHub.