{"record":{"id":"35b669a5eb7d7ecf","repo":"usebruno/bruno","slug":"request-filename-is-not-a-valid-filename","errorCode":null,"errorMessage":"${request.filename} is not a valid filename","messagePattern":"(.+?) is not a valid filename","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/bruno-electron/src/ipc/collection.js","lineNumber":554,"sourceCode":"  });\n\n  // new request\n  ipcMain.handle('renderer:new-request', async (event, pathname, request) => {\n    try {\n      if (fs.existsSync(pathname)) {\n        throw new Error(`path: ${pathname} already exists`);\n      }\n\n      const collectionPath = findCollectionPathByItemPath(pathname);\n      if (!collectionPath) {\n        throw new Error('Collection not found for the given pathname');\n      }\n      const format = getCollectionFormat(collectionPath);\n\n      // For the actual filename part, we want to be strict\n      const baseFilename = request?.filename?.replace(`.${format}`, '');\n      if (!validateName(baseFilename)) {\n        throw new Error(`${request.filename} is not a valid filename`);\n      }\n      validatePathIsInsideCollection(pathname);\n\n      const content = await stringifyRequestViaWorker(request, { format });\n      await writeFile(pathname, content);\n    } catch (error) {\n      return Promise.reject(error);\n    }\n  });\n\n  // save request\n  ipcMain.handle('renderer:save-request', async (event, pathname, request, format) => {\n    try {\n      if (!fs.existsSync(pathname)) {\n        throw new Error(`path: ${pathname} does not exist`);\n      }\n\n      validatePathIsInsideCollection(pathname);","sourceCodeStart":536,"sourceCodeEnd":572,"githubUrl":"https://github.com/usebruno/bruno/blob/9bdd81c7bdc57006e5f5ebffb79321a8d979f712/packages/bruno-electron/src/ipc/collection.js#L536-L572","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait window.ipcRenderer.invoke('renderer:save-new-request', pathname, { filename: 'GET /users', ... });\n\n// after\nconst clean = raw.replace(/[<>:\"/\\\\|?*\\x00-\\x1F]/g, '').trim().replace(/^[\\s-]+/, '').replace(/[.\\s]+$/, '');\nif (/^(CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9])$/i.test(clean)) throw new Error('reserved name');\nawait window.ipcRenderer.invoke('renderer:save-new-request', pathname, { filename: `${clean}.${format}`, ... });","handlingStrategy":"validation","validationCode":"// Replicates bruno-electron validateName (filesystem.js:291)\nfunction isValidRequestFilename(name) {\n  if (typeof name !== 'string' || name.length === 0 || name.length > 255) return false;\n  if (/^(CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9])$/i.test(name)) return false;\n  return /^[^\\s\\-<>:\"/\\\\|?*\\x00-\\x1F]/.test(name)\n    && /^[^<>:\"/\\\\|?*\\x00-\\x1F]*$/.test(name)\n    && /[^.\\s<>:\"/\\\\|?*\\x00-\\x1F]$/.test(name);\n}\n// strip the format extension the same way the handler does before validating\nconst base = request.filename.replace(/\\.(bru|yml)$/, '');\nif (!isValidRequestFilename(base)) throw new Error('invalid filename');","typeGuard":"function isCleanFilename(name) {\n  return typeof name === 'string'\n    && name.length > 0 && name.length <= 255\n    && !/^(CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9])$/i.test(name)\n    && /^[^\\s\\-<>:\"/\\\\|?*\\x00-\\x1F]/.test(name)\n    && /^[^<>:\"/\\\\|?*\\x00-\\x1F]*$/.test(name)\n    && /[^.\\s<>:\"/\\\\|?*\\x00-\\x1F]$/.test(name);\n}","tryCatchPattern":"try {\n  await window.ipcRenderer.invoke('renderer:save-new-request', pathname, request);\n} catch (e) {\n  if (/is not a valid filename/.test(e.message)) {\n    // sanitize and retry with a cleaned name, or surface to the user\n  } else throw e;\n}","preventionTips":["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."],"tags":["ipc","validation","filesystem","request","bruno"],"backgroundTag":null,"analyzedSha":"9bdd81c7bdc57006e5f5ebffb79321a8d979f712","analyzedAt":"2026-08-13T04:09:25.751Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}