elastic/elasticsearch · error · GradleException

No manifest digest found in OCI image layout index [{indexJs

Error message

No manifest digest found in OCI image layout index [{indexJson}]

What it means

Thrown by DockerBuildTask.resolveBuildContext() when an `oci-layout://` build-context value has no `@digest` suffix and the referenced layout's `index.json` does not contain a SHA-256 manifest digest matching `sha256:[a-f0-9]{64}`. The method resolves OCI-layout contexts by pinning the manifest digest so buildx references the image unambiguously; if no digest is found, the layout is malformed or empty and the build cannot proceed. This is a GradleException naming the index.json path.

Source

Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/docker/DockerBuildTask.java:345

        /**
         * Resolves an {@code oci-layout://} build context value to a digest-qualified reference.
         * Buildx resolves OCI layout contexts by tag or digest within the layout; the tag recorded
         * in the layout's index is not always what buildx looks up by default, so pinning the
         * manifest digest from {@code index.json} is the most robust way to reference the
         * (single-image) layouts we export.
         */
        private static String resolveBuildContext(String value) {
            String prefix = "oci-layout://";
            if (value.startsWith(prefix) == false || value.contains("@")) {
                return value;
            }
            Path indexJson = Path.of(value.substring(prefix.length()), "index.json");
            try {
                // The exported layouts contain a single manifest, so plucking the first digest is
                // sufficient and avoids a JSON parser dependency in this worker action.
                Matcher matcher = Pattern.compile("sha256:[a-f0-9]{64}").matcher(Files.readString(indexJson));
                if (matcher.find() == false) {
                    throw new GradleException("No manifest digest found in OCI image layout index [" + indexJson + "]");
                }
                return value + "@" + matcher.group();
            } catch (IOException e) {
                throw new UncheckedIOException("Failed to read OCI image layout index [" + indexJson + "]", e);
            }
        }

        private boolean isCrossPlatform() {
            return getParameters().getPlatforms()
                .get()
                .stream()
                .anyMatch(any -> any.equals(Architecture.current().dockerPlatform) == false);
        }

        private String getImageChecksum(String imageTag) {
            final ByteArrayOutputStream stdout = new ByteArrayOutputStream();
            String docker = getParameters().getDockerExecutable().get();

View on GitHub (pinned to db6a809a66)

Solutions

  1. Inspect the reported index.json: confirm it exists and contains a `"digest": "sha256:<64 lowercase hex>"` entry.
  2. Re-run whatever task exports/produces the OCI layout so index.json is regenerated correctly.
  3. If the digest is uppercase, regenerate the layout with a tool that emits lowercase, or fix the producer.
  4. Verify the `oci-layout://` path points at the correct layout directory (typo in build config).
Defensive patterns

Strategy: validation

Validate before calling

// Before building, for each oci-layout:// context assert index.json contains a lowercase sha256 digest:
// String json = Files.readString(indexJson);
// if (!Pattern.compile("sha256:[a-f0-9]{64}").matcher(json).find()) fail("no digest in " + indexJson);

Prevention

When it happens

Trigger: A Docker build is configured to use an `oci-layout://<path>` build context (typically pointing at an exported local layout). The path's `index.json` either does not exist as expected, is empty, or contains no `sha256:<64-hex>` digest. This happens when the layout export that was supposed to produce the context failed silently, produced an empty index, or wrote a digest in a format the regex does not recognize (e.g. uppercase hex).

Common situations: A prior task that exports the OCI layout failed or was skipped, leaving a partial/empty index.json; the layout was hand-constructed incorrectly; the digest uses uppercase A-F which the lowercase-only regex `[a-f0-9]` rejects; the path prefix `oci-layout://` was typo'd so the wrong directory is read.

Related errors


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