quarkusio/quarkus · error · UncheckedIOException

Unable to read ${resourceName} from ${path}

Error message

Unable to read ${resourceName} from ${path}

What it means

Channels.streamFor resolves a resource by name (classloader resource) and falls back to opening it as a file path. When neither the classloader resource exists nor Files.newInputStream(path) succeeds (file missing, unreadable, is a directory), the IOException is wrapped into an UncheckedIOException with the message 'Unable to read <resourceName> from <path>'. This is used e.g. for loading certificate/authority material when building gRPC channels.

Source

Thrown at extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/supports/Channels.java:268

    }

    private static Buffer bufferFor(Path path, String resourceName) throws IOException {
        try (InputStream stream = streamFor(path, resourceName)) {
            return Buffer.buffer(stream.readAllBytes());
        }
    }

    private static InputStream streamFor(Path path, String resourceName) {
        final InputStream resource = Thread.currentThread().getContextClassLoader()
                .getResourceAsStream(ClassPathUtils.toResourceName(path));
        if (resource != null) {
            return resource;
        } else {
            try {
                return Files.newInputStream(path);
            } catch (IOException e) {
                throw new UncheckedIOException("Unable to read " + resourceName + " from " + path, e);
            }
        }
    }

    @SuppressWarnings("unchecked")
    public static Channel retrieveChannel(String name, Set<String> perClientInterceptors) {
        ClientInterceptorStorage clientInterceptorStorage = Arc.container().instance(ClientInterceptorStorage.class).get();
        Annotation[] qualifiers = new Annotation[perClientInterceptors.size() + 1];
        int idx = 0;
        qualifiers[idx++] = GrpcClient.Literal.of(name);
        for (String interceptor : perClientInterceptors) {
            qualifiers[idx++] = RegisterClientInterceptor.Literal
                    .of((Class<? extends ClientInterceptor>) clientInterceptorStorage.getPerClientInterceptor(interceptor));
        }
        InstanceHandle<Channel> instance = Arc.container().instance(Channel.class, qualifiers);
        if (!instance.isAvailable()) {
            throw new IllegalStateException("Unable to retrieve the gRPC Channel " + name);
        }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Verify the path exists and is readable at runtime (ls/stat the exact path the process sees, including working directory for relative paths).
  2. Put the file under src/main/resources so it ships as a classpath resource, and reference it by resource name only.
  3. For native images/container builds, include the file (quarkus.native.resources.includes or volume mount) and use an absolute path.
  4. Check file permissions for the user running the Quarkus process.

Example fix

// before
quarkus.grpc.clients.hello.trust-store.pem.paths=./ca.pem  // not packaged

// after
# copy ca.pem to src/main/resources/certs/ca.pem
quarkus.grpc.clients.hello.trust-store.pem.paths=certs/ca.pem
Defensive patterns

Strategy: validation

Validate before calling

// ensure the trust/key material is resolvable before configuring the client
String path = "certs/ca.pem";
boolean asResource = Thread.currentThread().getContextClassLoader().getResource(path) != null
    || Channels.class.getClassLoader().getResource(path) != null;
boolean asFile = java.nio.file.Files.isRegularFile(java.nio.file.Path.of(path))
    && java.nio.file.Files.isReadable(java.nio.file.Path.of(path));
if (!asResource && !asFile) {
    throw new IllegalStateException("Resource/file not found or unreadable: " + path);
}

Try / catch

try {
    channel = Channels.createChannel("hello", interceptors);
} catch (UncheckedIOException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Unable to read")) {
        throw new ConfigurationException("Package the resource into the app (src/main/resources) or fix the path: " + e.getMessage(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Configuring a gRPC client (e.g. trust-store / key-store path or SSL material) with a path/resource name that neither matches a classpath resource nor an existing readable file, so streamFor('name', 'path') fails on both branches during channel creation.

Common situations: Typo in the certificate path; file present in dev but not packaged into the native image or container; relative path resolved against a different working directory at runtime; file permissions deny read for the running user.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/82d0a8abc1e17360. Report an issue: GitHub.