{"record":{"id":"a389bd91a3e2f59d","repo":"theonedev/onedev","slug":"file-path-has-to-be-specified","errorCode":null,"errorMessage":"File path has to be specified","messagePattern":"File path has to be specified","errorType":"exception","errorClass":"ExplicitException","httpStatus":null,"severity":"error","filePath":"server-plugin/server-plugin-report-html/src/main/java/io/onedev/server/plugin/report/html/HtmlReportDownloadResource.java","lineNumber":69,"sourceCode":"\t\tString reportName = params.get(PARAM_REPORT).toString();\n\t\tif (reportName.contains(\"..\"))\n\t\t\tthrow new ExplicitException(\"Invalid request path\");\n\n\t\tif (!SecurityUtils.canAccessReport(build, reportName))\n\t\t\tthrow new UnauthorizedException();\n\n\t\tList<String> pathSegments = new ArrayList<>();\n\n\t\tfor (int i = 0; i < params.getIndexedCount(); i++) {\n\t\t\tString pathSegment = params.get(i).toString();\n\t\t\tif (pathSegment.contains(\"..\"))\n\t\t\t\tthrow new ExplicitException(\"Invalid request path\");\n\t\t\tif (pathSegment.length() != 0)\n\t\t\t\tpathSegments.add(pathSegment);\n\t\t}\n\n\t\tif (pathSegments.isEmpty())\n\t\t\tthrow new ExplicitException(\"File path has to be specified\");\n\n\t\tvar filePath = Joiner.on(\"/\").join(pathSegments);\n\t\tvar fileName = filePath;\n\t\tif (fileName.contains(\"/\"))\n\t\t\tfileName = StringUtils.substringAfterLast(fileName, \"/\");\n\t\t\n\t\tResourceResponse response = new ResourceResponse();\n\t\ttry {\n\t\t\tresponse.setContentType(Files.probeContentType(Paths.get(filePath)));\n\t\t} catch (IOException e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t\tresponse.disableCaching();\n\t\tresponse.setFileName(URLEncoder.encode(fileName, UTF_8));\n\t\t\n\t\tresponse.setWriteCallback(new WriteCallback() {\n\n\t\t\t@Override","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-plugin/server-plugin-report-html/src/main/java/io/onedev/server/plugin/report/html/HtmlReportDownloadResource.java#L51-L87","documentation":"After validating segments, HtmlReportDownloadResource requires at least one non-empty path segment; otherwise it throws 'File path has to be specified'. The resource serves a specific file of the HTML report, so a request identifying only the report (no file) cannot be fulfilled.","triggerScenarios":"GET on the html report download resource where all indexed path params are empty or absent — the URL points at the report but not a file within it.","commonSituations":"Trailing-slash URLs with no file part; links generated to the report root instead of e.g. index.html; truncation of the URL by templates.","solutions":["Append the target file path to the resource URL (e.g. .../index.html)","Point links at the report index page rather than the report root","Ensure the link template does not drop the file segment"],"exampleFix":"// before\nGET /~resources/html-report/proj/12/report/\n// after\nGET /~resources/html-report/proj/12/report/index.html","handlingStrategy":"validation","validationCode":"const filePath = segments.filter(Boolean).join('/');\nif (!filePath) throw new Error('File path has to be specified');","typeGuard":"const hasFilePart = (parts) => Array.isArray(parts) && parts.filter(p => p && p.length).length > 0;","tryCatchPattern":"try { fetch(url); } catch (ExplicitException e) { // append default index.html and retry }","preventionTips":["Always append a concrete file (e.g. index.html) to report download URLs","Filter empty segments when composing URLs from variables","Default to the report entry page when no file is known"],"tags":["rest","report","missing-argument"],"backgroundTag":"missing-required-argument","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}