elastic/elasticsearch · error · RuntimeException
Two different notices exist for dependency '${name}': ${prev
Error message
Two different notices exist for dependency '${name}': ${prevFile} and ${file} What it means
Thrown by NoticeTask.generateNotice when two NOTICE files for the same dependency name (the filename with the '-NOTICE.txt' suffix stripped) are found in the configured license directories and their textual contents differ. The task de-duplicates by dependency name so each component appears once in the aggregated NOTICE; conflicting notices for one name indicate a licensing inconsistency that must be resolved manually.
Source
Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/NoticeTask.java:116
}
@TaskAction
public void generateNotice() throws IOException {
StringBuilder output = new StringBuilder();
output.append(readFileToString(inputFile, "UTF-8"));
output.append("\n\n");
// This is a map rather than a set so that the sort order is the 3rd
// party component names, unaffected by the full path to the various files
final Map<String, File> seen = new TreeMap<String, File>();
FileCollection noticeFiles = getNoticeFiles();
if (noticeFiles != null) {
for (File file : getNoticeFiles()) {
String name = file.getName().replaceFirst("-NOTICE\\.txt$", "");
if (seen.containsKey(name)) {
File prevFile = seen.get(name);
String previousFileText = readFileToString(prevFile, "UTF-8");
if (previousFileText.equals(readFileToString(file, "UTF-8")) == false) {
throw new RuntimeException(
"Two different notices exist for dependency '" + name + "': " + prevFile + " and " + file
);
}
} else {
seen.put(name, file);
}
}
}
// Add all LICENSE and NOTICE files in licenses directory
seen.forEach((name, file) -> {
appendFile(file, name, "NOTICE", output);
appendFile(new File(file.getParentFile(), name + "-LICENSE.txt"), name, "LICENSE", output);
});
// Find any source files with "@notice" annotated license header
for (File sourceFile : sources.getFiles()) {
boolean isPackageInfo = sourceFile.getName().equals("package-info.java");View on GitHub (pinned to db6a809a66)
Solutions
- Identify both file paths in the message; open them and reconcile the content — keep a single canonical NOTICE for that dependency.
- If the old file is stale (dependency upgraded), delete the obsolete '-NOTICE.txt' so only the current one remains.
- If the two files are meant for genuinely different artifacts, rename one so the stripped name differs (e.g. 'jackson-databind-NOTICE.txt' vs 'jackson-core-NOTICE.txt').
- Ensure identical line endings and no trailing-whitespace drift if the notices are supposed to be equal.
Example fix
// before: licenses/jackson-core-NOTICE.txt and licenses/jackson-core-NOTICE.txt.bak differ // after: delete the stale .bak / duplicate file so only one jackson-core-NOTICE.txt remains
Defensive patterns
Strategy: validation
Validate before calling
// Before the build, assert no dependency has two divergent NOTICE files:
import java.nio.file.*;
import java.util.*;
Map<String, Path> seen = new TreeMap<>();
try (var s = Files.list(Path.of("licenses"))) {
s.filter(p -> p.getFileName().toString().endsWith("-NOTICE.txt")).forEach(p -> {
String key = p.getFileName().toString().replaceFirst("-NOTICE\\.txt$", "");
if (seen.containsKey(key)) {
String a = Files.readString(seen.get(key));
String b = Files.readString(p);
if (!a.equals(b)) throw new IllegalStateException(
"conflict for " + key + ": " + seen.get(key) + " vs " + p);
} else seen.put(key, p);
});
} Prevention
- When upgrading a dependency, replace its old '-NOTICE.txt' rather than adding a second one.
- Give each NOTICE file a unique dependency-name key (the part before '-NOTICE.txt').
- Normalize line endings before committing NOTICE files; the comparison is exact.
When it happens
Trigger: getNoticeFiles() collects '**/*-NOTICE.txt' across getLicenseDirs() (default: ${projectDir}/licenses plus any added via licensesDir). For each file, the name key is fileName.replaceFirst("-NOTICE\\.txt$", ""). If the key was seen before, both files are read as UTF-8 and compared; a byte-level difference throws.
Common situations: A dependency upgrade ships a new NOTICE whose text differs, but the old '-NOTICE.txt' was not removed/updated; two dependencies sharing a base name (e.g. 'jackson-core' vs 'jackson-core-annotations') collide after stripping; merge conflicts leaving two NOTICE files for the same component; line-ending or trailing-whitespace differences (the comparison is exact, not normalized).
Related errors
- expected [${noticePath} to contain [${expectedLine}] but it
- Failed to patch archive
- Failed to unpack {} with checksum {}
- Missing "from" setting for license name mapping
- Missing "to" setting for license name mapping
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/4a440bfa1f256c24.
Report an issue: GitHub.