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
- Inspect the reported index.json: confirm it exists and contains a `"digest": "sha256:<64 lowercase hex>"` entry.
- Re-run whatever task exports/produces the OCI layout so index.json is regenerated correctly.
- If the digest is uppercase, regenerate the layout with a tool that emits lowercase, or fix the producer.
- 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
- Ensure the OCI-layout-producing task runs before the Docker build task (declare a proper task dependency).
- Verify exported layouts contain a lowercase sha256 digest in index.json.
- Double-check the `oci-layout://` path spelling in build config.
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
- Failed to read OCI image layout index [{indexJson}]
- classname is a required setting for esplugin
- classname is a forbidden for stable esplugin
- invalid deploymentTarget '{}', expected one of {}
- unrecognized classpath entry: {}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/714962aec6f2a884.
Report an issue: GitHub.