GoogleContainerTools/jib · error · UnknownManifestFormatException

Cannot find field 'schemaVersion' in manifest

Error message

Cannot find field 'schemaVersion' in manifest

What it means

Thrown by AbstractManifestPuller.getManifestTemplateFromJson when the manifest JSON returned by the registry lacks a 'schemaVersion' field. Jib uses that field to decide between Docker V2.1/V2.2 and OCI manifest formats, so a manifest without it cannot be interpreted. It surfaces as UnknownManifestFormatException.

Source

Thrown at jib-core/src/main/java/com/google/cloud/tools/jib/registry/AbstractManifestPuller.java:140

  @Override
  public String getActionDescription() {
    return "pull image manifest for "
        + registryEndpointRequestProperties.getServerUrl()
        + "/"
        + registryEndpointRequestProperties.getImageName()
        + ":"
        + imageQualifier;
  }

  /**
   * Instantiates a {@link ManifestTemplate} from a JSON string. This checks the {@code
   * schemaVersion} field of the JSON to determine which manifest version to use.
   */
  private T getManifestTemplateFromJson(String jsonString)
      throws IOException, UnknownManifestFormatException {
    ObjectNode node = new ObjectMapper().readValue(jsonString, ObjectNode.class);
    if (!node.has("schemaVersion")) {
      throw new UnknownManifestFormatException("Cannot find field 'schemaVersion' in manifest");
    }

    int schemaVersion = node.get("schemaVersion").asInt(-1);
    if (schemaVersion == -1) {
      throw new UnknownManifestFormatException("'schemaVersion' field is not an integer");
    }

    if (schemaVersion == 1) {
      return manifestTemplateClass.cast(
          JsonTemplateMapper.readJson(jsonString, V21ManifestTemplate.class));
    }
    if (schemaVersion == 2) {
      // 'schemaVersion' of 2 can be either Docker V2.2 or OCI.
      JsonNode mediaTypeNode = node.get("mediaType");
      if (mediaTypeNode == null) { // not Docker, hence OCI
        if (node.get("manifests") != null) {
          return manifestTemplateClass.cast(
              JsonTemplateMapper.readJson(jsonString, OciIndexTemplate.class));

View on GitHub (pinned to fb949e2676)

Solutions

  1. Verify the registry URL points to a real Docker Registry v2 endpoint, not a proxy or UI page.
  2. Inspect the raw response with curl (Accept: application/vnd.docker.distribution.manifest.v2+json) to see what the server returns.
  3. Check proxy/mirror configuration so it forwards registry responses unmodified.
  4. If the registry is third-party, confirm it supports the Docker Registry HTTP API v2.
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: confirm registry serves a v2 manifest
// curl -sI -H "Accept: application/vnd.docker.distribution.manifest.v2+json" https://registry.example.com/v2/<image>/manifests/<tag>
// response JSON must contain a numeric "schemaVersion"

Try / catch

// catch RegistryErrorException and surface registry/proxy diagnostics
try {
    jibContainerBuilder.containerize();
} catch (RegistryErrorException e) {
    if (e.getMessage().contains("schemaVersion")) {
        throw new IllegalStateException("Registry did not return a valid v2 manifest — check proxy/registry config", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Pulling a manifest from an endpoint that returns non-standard JSON (e.g. an HTML error page, an API response, or a registry proxy stripping fields) while Jib expects a Docker/OCI manifest.

Common situations: Registry misconfiguration behind a proxy/mirror that returns custom JSON, an auth page returned instead of the manifest, or a very old/nonconforming registry.

Related errors


AI-assisted analysis of GoogleContainerTools/jib@fb949e2676 (2026-09-06). Data as JSON: /api/errors/0697e548bc59f5c2. Report an issue: GitHub.