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

  1. Identify both file paths in the message; open them and reconcile the content — keep a single canonical NOTICE for that dependency.
  2. If the old file is stale (dependency upgraded), delete the obsolete '-NOTICE.txt' so only the current one remains.
  3. 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').
  4. 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 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


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/4a440bfa1f256c24. Report an issue: GitHub.