{"record":{"id":"8e4ba1cf13d2ba3f","repo":"OtterMind/Chat2DB","slug":"ai-attachment-filenotfound","errorCode":"ai.attachment.fileNotFound","errorMessage":"ai.attachment.fileNotFound","messagePattern":"ai\\.attachment\\.fileNotFound","errorType":"exception","errorClass":"BusinessException","httpStatus":null,"severity":"error","filePath":"chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiAttachmentServiceImpl.java","lineNumber":72,"sourceCode":"    public ChatAttachment parse(AiAttachmentParseRequest param) {\n        if (param == null || param.getInputStream() == null) {\n            throw new BusinessException(\"ai.attachment.inputStreamRequired\");\n        }\n        String fileName = StringUtils.defaultIfBlank(param.getFileName(), \"attachment\");\n        try (InputStream inputStream = param.getInputStream()) {\n            return parse(fileName, inputStream);\n        } catch (IOException e) {\n            throw new BusinessException(\"ai.attachment.parseFailed\", new Object[]{fileName, e.getMessage()}, e);\n        }\n    }\n\n    public ChatAttachment parse(AiLocalAttachmentParseRequest param) {\n        if (param == null || StringUtils.isBlank(param.getFilePath())) {\n            throw new BusinessException(\"ai.attachment.filePathRequired\");\n        }\n        File file = new File(param.getFilePath().trim());\n        if (!file.exists() || !file.isFile()) {\n            throw new BusinessException(\"ai.attachment.fileNotFound\");\n        }\n        String fileName = StringUtils.defaultIfBlank(param.getFileName(), file.getName());\n        try (InputStream inputStream = new FileInputStream(file)) {\n            return parse(fileName, inputStream);\n        } catch (IOException e) {\n            throw new BusinessException(\"ai.attachment.localParseFailed\", new Object[]{file.getPath(), e.getMessage()}, e);\n        }\n    }\n\n    public String buildStructuredContext(List<ChatAttachment> attachments) {\n        if (CollectionUtils.isEmpty(attachments)) {\n            return null;\n        }\n        StringBuilder builder = new StringBuilder(4096);\n        builder.append(\"Uploaded file context for the current conversation. \");\n        builder.append(\"Treat it as user-provided evidence. \");\n        builder.append(\"If the parsed content is truncated, say so when it affects certainty.\\n\");\n","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/OtterMind/Chat2DB/blob/5ee1e990e73fbcae1969dc554be254fedb3ab888/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiAttachmentServiceImpl.java#L54-L90","documentation":"Thrown by AiAttachmentServiceImpl.parse(AiLocalAttachmentParseRequest) after constructing new File(filePath.trim()) when the path does not exist or is not a regular file (e.g. it points at a directory). The i18n message resolves to 'File does not exist'. It is a pre-parse guard so the service never opens a missing or non-file target.","triggerScenarios":"param.getFilePath() resolves to a path that does not exist on the server filesystem, OR points to a directory, OR the path was a temporary upload that was already cleaned up. Triggered by: new File(param.getFilePath().trim()) where !file.exists() || !file.isFile().","commonSituations":"Temp upload file was deleted between the upload and parse call; the desktop renderer passed a client-side path that does not exist on the server; a relative path resolved against an unexpected working directory; the path points to a folder rather than a file; stale path cached after a move/rename.","solutions":["Verify the file exists at the server path before calling parse(), and re-check the temp-upload lifecycle so the file is not GC'd early.","Use absolute server paths; never pass client machine paths from the renderer to the server-side local parse overload.","If the upload produced an InputStream, switch to parse(AiAttachmentParseRequest) which does not require an existing server file."],"exampleFix":"// before\nreq.setFilePath(tempPath); // tempPath already deleted\nservice.parse(req);\n\n// after\nFile f = new File(tempPath);\nif (!f.isFile()) {\n    return ResponseEntity.badRequest().body(\"file is missing, re-upload\");\n}\nreq.setFilePath(f.getAbsolutePath());\nservice.parse(req);","handlingStrategy":"validation","validationCode":"File f = new File(param.getFilePath().trim());\nif (!f.exists() || !f.isFile()) {\n    return ResponseEntity.badRequest().body(\"file does not exist: \" + f);\n}\nservice.parse(param);","typeGuard":null,"tryCatchPattern":"try {\n    service.parse(param);\n} catch (BusinessException e) {\n    if (\"ai.attachment.fileNotFound\".equals(e.getCode())) {\n        return ResponseEntity.badRequest().body(\"re-upload the file\");\n    }\n    throw e;\n}","preventionTips":["Keep temp uploads alive for the full parse lifecycle; do not GC them on a separate schedule.","Pass absolute server paths, never renderer/client paths.","Re-check existence right before parse if there is any cleanup running concurrently."],"tags":["ai","attachment","filesystem","input-validation"],"backgroundTag":null,"analyzedSha":"5ee1e990e73fbcae1969dc554be254fedb3ab888","analyzedAt":"2026-08-14T07:05:03.077Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}