GoogleContainerTools/jib · error · UnsupportedOperationException

Cannot apply includes/excludes on single file copy directive

Error message

Cannot apply includes/excludes on single file copy directives.

What it means

In Layers.toLayers, include/exclude filters are only supported for directory copy directives. When src is a single regular file and the copy spec declares any includes or excludes, the CLI throws UnsupportedOperationException with this message.

Source

Thrown at jib-cli/src/main/java/com/google/cloud/tools/jib/cli/buildfile/Layers.java:87

        layerBuiler.setName(fileLayer.getName());
        // layer properties
        fileLayer.getProperties().ifPresent(filePropertiesStack::push);
        for (CopySpec copySpec : ((FileLayerSpec) entry).getFiles()) {
          // copy spec properties
          copySpec.getProperties().ifPresent(filePropertiesStack::push);

          // relativize all paths to the buildRoot location
          Path rawSrc = copySpec.getSrc();
          Path src = rawSrc.isAbsolute() ? rawSrc : buildRoot.resolve(rawSrc);
          AbsoluteUnixPath dest = copySpec.getDest();

          if (!Files.isDirectory(src) && !Files.isRegularFile(src)) {
            throw new UnsupportedOperationException(
                "Cannot create FileLayers from non-file, non-directory: " + src.toString());
          }
          if (Files.isRegularFile(src)) { // regular file
            if (!copySpec.getExcludes().isEmpty() || !copySpec.getIncludes().isEmpty()) {
              throw new UnsupportedOperationException(
                  "Cannot apply includes/excludes on single file copy directives.");
            }
            layerBuiler.addEntry(
                src,
                copySpec.isDestEndsWithSlash() ? dest.resolve(src.getFileName()) : dest,
                filePropertiesStack.getFilePermissions(),
                filePropertiesStack.getModificationTime(),
                filePropertiesStack.getOwnership());
          } else if (Files.isDirectory(src)) { // directory
            List<PathMatcher> excludes =
                copySpec.getExcludes().stream()
                    .map(Layers::toPathMatcher)
                    .collect(Collectors.toList());
            List<PathMatcher> includes =
                copySpec.getIncludes().stream()
                    .map(Layers::toPathMatcher)
                    .collect(Collectors.toList());
            try (Stream<Path> dirWalk = Files.walk(src)) {

View on GitHub (pinned to fb949e2676)

Solutions

  1. Remove the includes/excludes arrays from single-file copy directives.
  2. Point src at the parent directory and use excludes/includes to narrow down to the desired file.
  3. Restructure the spec so filtering applies only to directory sources.

Example fix

// before
{"src": "app.jar", "dest": "/app", "excludes": ["*.tmp"]}
// after
{"src": "app.jar", "dest": "/app"}
Defensive patterns

Strategy: validation

Validate before calling

if (Files.isRegularFile(buildRoot.resolve(spec.getSrc()))
    && (!spec.getExcludes().isEmpty() || !spec.getIncludes().isEmpty())) {
  throw new IllegalStateException("includes/excludes not allowed on single-file copy: " + spec.getSrc());
}

Prevention

When it happens

Trigger: A build file copy spec where src resolves to a single regular file and either 'excludes' or 'includes' is non-empty, e.g. {"src": "app.jar", "dest": "/app", "excludes": ["*.tmp"]}.

Common situations: Copy-pasting a directory copy spec and changing src to a file while leaving filter options in place.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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