{"id":"5a6db2e8e12d5614","repo":"junit-team/junit5","slug":"failed-to-retrieve-canonical-path-for-file-file-5a6db2","errorCode":null,"errorMessage":"Failed to retrieve canonical path for file: ${file}","messagePattern":"Failed to retrieve canonical path for file: (.+?)","errorType":"exception","errorClass":"JUnitException","httpStatus":null,"severity":"error","filePath":"junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSource.java","lineNumber":77,"sourceCode":"\tpublic static FileSource from(File file, @Nullable FilePosition filePosition) {\n\t\treturn new FileSource(file, filePosition);\n\t}\n\n\tprivate final File file;\n\n\tprivate final @Nullable FilePosition filePosition;\n\n\tprivate FileSource(File file) {\n\t\tthis(file, null);\n\t}\n\n\tprivate FileSource(File file, @Nullable FilePosition filePosition) {\n\t\tPreconditions.notNull(file, \"file must not be null\");\n\t\ttry {\n\t\t\tthis.file = file.getCanonicalFile();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new JUnitException(\"Failed to retrieve canonical path for file: \" + file, ex);\n\t\t}\n\t\tthis.filePosition = filePosition;\n\t}\n\n\tprivate FileSource(FileSource fileSource, @Nullable FilePosition filePosition) {\n\t\tthis.file = fileSource.file;\n\t\tthis.filePosition = filePosition;\n\t}\n\n\t/**\n\t * Get the {@link URI} for the source {@linkplain #getFile file}.\n\t *\n\t * @return the source {@code URI}; never {@code null}\n\t */\n\t@Override\n\tpublic URI getUri() {\n\t\treturn getFile().toURI();\n\t}","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/junit-team/junit5/blob/956246301e03d757539f7b76dd5a91f298637563/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSource.java#L59-L95","documentation":"Thrown by the FileSource constructor (line 71-80) when file.getCanonicalFile() raises IOException, wrapped in a JUnitException. FileSource.from(File) attaches a file as a TestSource. Like DirectorySource, no existence check is performed here.","triggerScenarios":"Calling FileSource.from(file) (or FileSource.from(file, position)) for a file whose canonical path cannot be resolved (broken symlink, missing parent directory, filesystem I/O error, unreachable mount).","commonSituations":"Custom engine/extension building a file-backed TestSource for a stale or broken path; test descriptors cached across filesystem changes; CI on ephemeral filesystems; symlinks pointing to deleted originals.","solutions":["Pre-canonicalize with Path.toRealPath().toFile() and pass the resolved File to FileSource.from(...).","Guard with Files.isRegularFile(Path) before constructing.","Use the withPosition(FilePosition) method on an existing FileSource to add positions, avoiding repeated canonical resolution (per its javadoc at line 130).","Inspect the caused-by IOException for the root filesystem fault."],"exampleFix":"// before\nTestSource source = FileSource.from(new File(filePath), FilePosition.from(42).orElse(null));\n\n// after\nFile canonical = Path.of(filePath).toRealPath().toFile();\nTestSource source = FileSource.from(canonical, FilePosition.from(42).orElse(null));","handlingStrategy":"validation","validationCode":"File canonical = Path.of(filePath).toRealPath().toFile();\nTestSource source = FileSource.from(canonical, position);","typeGuard":null,"tryCatchPattern":"try {\n    return FileSource.from(file);\n} catch (JUnitException e) {\n    throw new IllegalStateException(\"cannot build FileSource for \" + file, e.getCause());\n}","preventionTips":["Pre-canonicalize via Path.toRealPath().toFile().","Use FileSource.withPosition() to add positions without re-resolving the canonical path.","Guard with Files.isRegularFile(Path)."],"tags":["junit-platform","test-source","io","filesystem","file-source","canonical-path"],"analyzedSha":"956246301e03d757539f7b76dd5a91f298637563","analyzedAt":"2026-08-04T19:25:17.049Z","schemaVersion":2}