{"record":{"id":"959b38d2828036ea","repo":"Mintplex-Labs/anything-llm","slug":"invalid-filename-format","errorCode":null,"errorMessage":"Invalid filename format","messagePattern":"Invalid filename format","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"server/endpoints/agentFileServer.js","lineNumber":43,"sourceCode":"   * Download a generated file by its storage filename.\n   * Validates that the requesting user has access to the workspace\n   * where the file was generated.\n   */\n  app.get(\n    \"/agent-skills/generated-files/:filename\",\n    [validatedRequest, flexUserRoleValid([ROLES.all])],\n    async (request, response) => {\n      try {\n        const user = await userFromSession(request, response);\n        const { filename } = request.params;\n        if (!filename)\n          return response.status(400).json({ error: \"Filename is required\" });\n\n        // Validate filename format\n        const parsed = createFilesLib.parseFilename(filename);\n        if (!parsed) {\n          return response\n            .status(400)\n            .json({ error: \"Invalid filename format\" });\n        }\n\n        // Find a chat or scheduled job run that references this file\n        const fileSource = await findFileSource(filename, {\n          user,\n          isMultiUser: multiUserMode(response),\n        });\n\n        if (!fileSource) {\n          return response.status(404).json({\n            error: \"File not found or access denied\",\n          });\n        }\n\n        // Retrieve the file from storage\n        const fileData = await createFilesLib.getGeneratedFile(filename);\n        if (!fileData) {","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/server/endpoints/agentFileServer.js#L25-L61","documentation":"Returned (HTTP 400) by GET /agent-skills/generated-files/:filename when createFilesLib.parseFilename(filename) returns null. The filename must match the generated-file naming scheme {fileType}-{36-char uuid}.{extension} (regex /^([a-z]+)-([a-f0-9-]{36})\\.(\\w+)$/i in create-files/lib.js:194) because the endpoint only serves files created by the agent's file-creation tool. Human-readable names, missing extensions, wrong UUID length, or extra characters all fail here before any database or storage lookup.","triggerScenarios":"GET /agent-skills/generated-files/report.pdf (display name instead of storage name like pptx-3f2c...-uuid.pptx); filename with no dot/extension; a uuid segment shorter than 36 chars; path separators or '..' smuggled into the param; double-encoded names that decode after the route match.","commonSituations":"Users copying the pretty display filename from chat instead of the download link; clients building URLs from the original prompt title; copy/paste truncating the long uuid; URL-encoding differences (%20 vs +) mangling the name.","solutions":["Use the exact storage filename from the chat's artifact/download URL — never the human-readable display name","If constructing links yourself, build them as `${fileType}-${uuid}.${ext}` matching the 36-char uuid convention","Check for double-encoding when names pass through proxies or query strings"],"exampleFix":"// before: display name does not match the storage scheme\nconst url = `/agent-skills/generated-files/${encodeURIComponent('Q3 Report.pptx')}`; // 400\n\n// after: take the storage filename the backend returned with the artifact\nconst url = `/agent-skills/generated-files/${encodeURIComponent(artifact.storageFilename)}`; // e.g. pptx-<uuid>.pptx","handlingStrategy":"type-guard","validationCode":"const GENERATED_FILE_PATTERN = /^([a-z]+)-([a-f0-9-]{36})\\.(\\w+)$/i;\nif (!GENERATED_FILE_PATTERN.test(filename))\n  throw new Error(`not a storage filename: ${filename}`);","typeGuard":"function isStorageFilename(filename) {\n  return typeof filename === 'string' &&\n    /^([a-z]+)-([a-f0-9-]{36})\\.(\\w+)$/i.test(filename);\n}","tryCatchPattern":"try { const blob = await download(filename); }\ncatch (e) {\n  if (e.status === 400 && /filename format/i.test(e.body?.error ?? ''))\n    throw new Error(`use the artifact's storage filename, not its display name`);\n}","preventionTips":["Carry the storage filename (fileType-uuid.ext) through your app state; derive URLs only from it","Never build these URLs from user-visible titles","Keep the client-side regex in sync with parseFilename in server/utils/agents/aibitat/plugins/create-files/lib.js"],"tags":["http-400","filename-validation","file-download","uuid-format"],"backgroundTag":"invalid-filename-format","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","contentChangedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}