flowable/flowable-engine · error · UncheckedIOException

Failed to read mappings

Error message

Failed to read mappings 

What it means

Thrown (as UncheckedIOException) by FlowableMyBatisResourceHintsRegistrar.registerMappingResources when the MyBatis configuration file referenced by mappingsPath cannot be read while registering AOT/native-image reflection and resource hints. IOException from classpath loading or stream opening is wrapped with the failing path in the message.

Solutions

  1. Verify the mappings path configured for the engine exists on the classpath (org/flowable/db/mapping/...xml) and is spelled correctly.
  2. Ensure the XML files are included in the build artifact (check Maven resource filtering / Gradle processResources excludes).
  3. Register the MyBatis XML resources as native-image resources (resources.includes) so AOT can read them.
  4. Check that the file is valid XML and openable via the configured ClassLoader (test classLoader.getResourceAsStream(mappingsPath)).

Example fix

// before
<resource><directory>src/main/resources</directory><excludes><exclude>**/*.xml</exclude></excludes></resource>
// after
<resource><directory>src/main/resources</directory><includes><include>**/*.xml</include></includes></resource>
Defensive patterns

Strategy: validation

Validate before calling

try (InputStream in = classLoader.getResourceAsStream(mappingsPath)) {
  if (in == null) throw new IllegalStateException("MyBatis config not on classpath: " + mappingsPath);
}

Try / catch

try {
  registrar.registerHints(runtimeHints, classLoader);
} catch (UncheckedIOException e) {
  if (e.getMessage().startsWith("Failed to read mappings")) {
    log.error("MyBatis mappings missing/unreadable at AOT time: {}", mappingsPath, e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Spring native/GraalVM AOT processing with a mappings path that is missing from the classpath, unreadable, or malformed so parsing fails with an IOException.

Common situations: Wrong mybatis mappings config property (typo in resource path); resource not packaged in a fat jar or native image; resources filtering stripping the XML; running with a stripped classpath in AOT build.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/40c1d5eef379f1da. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableMyBatisResourceHintsRegistrar.java:52

 *
 * @author Filip Hrisafov
 */
public class FlowableMyBatisResourceHintsRegistrar {

    public static void registerMappingResources(String baseFolder, RuntimeHints runtimeHints, ClassLoader classLoader) {
        ResourceHints resourceHints = runtimeHints.resources();
        String mappingsPath = baseFolder + "/mappings.xml";
        ClassPathResource mappingsResource = new ClassPathResource(mappingsPath);
        resourceHints.registerResource(mappingsResource);
        try (InputStream mappingsStream = mappingsResource.getInputStream()) {
            XPathParser parser = createParser(mappingsStream);

            List<XNode> mappers = parser.evalNodes("/configuration/mappers/mapper");
            for (XNode mapper : mappers) {
                registerMapper(mapper.getStringAttribute("resource"), runtimeHints, classLoader);
            }
        } catch (IOException e) {
            throw new UncheckedIOException("Failed to read mappings " + mappingsPath, e);
        }
    }

    public static void registerMapper(String mapperPath, RuntimeHints hints, ClassLoader classLoader) {
        ResourceHints resourceHints = hints.resources();
        ClassPathResource mapperResource = new ClassPathResource(mapperPath);
        resourceHints.registerResource(mapperResource);

        ReflectionHints reflectionHints = hints.reflection();
        MemberCategory[] memberCategories = MemberCategory.values();
        try (InputStream mapperStream = mapperResource.getInputStream()) {
            XPathParser parser = createParser(mapperStream);
            XNode mapper = parser.evalNode("/mapper");
            // The xpath resolving is similar like what MyBatis does in XMLMapperBuilder#parse
            for (XNode resultMap : mapper.evalNodes("/mapper/resultMap")) {
                String type = resultMap.getStringAttribute("type");
                if (type != null) {
                    reflectionHints.registerType(TypeReference.of(type), memberCategories);

View on GitHub (pinned to d6d39ce1c6)