Skip to content

BPMN schema validation fails when Flowable jar is loaded from a non-ASCII unpacked Spring Boot classpath #4214

@li-zhixin

Description

@li-zhixin

Description

We encountered a BPMN schema validation failure in Flowable 7.2.0 when the Flowable dependency jar is loaded from an unpacked Spring Boot executable jar located under a path containing non-ASCII characters.

The BPMN XML itself is valid. The failure happens during Flowable's default BPMN schema validation.

Environment

  • Flowable: 7.2.0
  • Spring Boot: 3.2.12
  • Deployment style: unpacked executable jar, started with org.springframework.boot.loader.launch.JarLauncher
  • Java: reproduced on Java 17 / Java 21
  • OS: Windows
  • Runtime path contains non-ASCII characters, for example:
D:/workspace/流程/runtime/.runtime.jar.exploded/BOOT-INF/lib/flowable-bpmn-converter-7.2.0.jar

Why the classpath contains non-ASCII characters

Our application uses Spring Boot's efficient deployment style by unpacking the executable jar before startup.

This is similar to the deployment approach described in the Spring Boot reference documentation:

https://docs.spring.io/spring-boot/docs/3.2.12/reference/html/deployment.html#deployment.efficient.unpacking

In this mode, the executable jar is exploded and the application is started from the unpacked directory. The runtime classpath then contains entries such as:

<workspace>/runtime/.runtime.jar.exploded/BOOT-INF/classes
<workspace>/runtime/.runtime.jar.exploded/BOOT-INF/lib/*

We use this deployment mode mainly to improve cold startup time.

The <workspace> directory is user-controlled. In desktop, local-runtime, or embedded-runtime scenarios, this directory can naturally contain localized names, for example:

D:/workspace/流程/runtime/.runtime.jar.exploded/BOOT-INF/lib/flowable-bpmn-converter-7.2.0.jar

Therefore, the Flowable dependency jar becomes part of a classpath whose physical path contains non-ASCII characters.

This is not related to the BPMN file name or BPMN content. It is a consequence of running a valid Spring Boot unpacked deployment from a localized workspace path.

Actual Error From Our Application

Application-specific package names and local paths are anonymized below, but the Flowable, Spring Boot, JDK, and Xerces stack frames are unchanged.

2026-06-02 13:32:08.701 [main] ERROR o.f.e.impl.bpmn.deployer.ParsedDeploymentBuilder - Could not parse resource process1.bpmn
org.flowable.bpmn.exceptions.XMLException: src-resolve: Cannot resolve the name 'extension' to a(n) 'element declaration' component.

at org.flowable.bpmn.converter.BpmnXMLConverter.convertToBpmnModel(BpmnXMLConverter.java:292)
at org.flowable.engine.impl.bpmn.parser.BpmnParse.execute(BpmnParse.java:148)
at org.flowable.engine.impl.bpmn.deployer.ParsedDeploymentBuilder.createBpmnParseFromResource(ParsedDeploymentBuilder.java:97)
at org.flowable.engine.impl.bpmn.deployer.ParsedDeploymentBuilder.build(ParsedDeploymentBuilder.java:55)
at org.flowable.engine.impl.bpmn.deployer.BpmnDeployer.deploy(BpmnDeployer.java:78)
at org.flowable.engine.impl.persistence.deploy.DeploymentManager.deploy(DeploymentManager.java:62)
at org.flowable.engine.impl.cmd.DeployCmd.executeDeploy(DeployCmd.java:135)
at org.flowable.engine.impl.cmd.DeployCmd.execute(DeployCmd.java:70)
at org.flowable.engine.impl.cmd.DeployCmd.execute(DeployCmd.java:45)
at org.flowable.engine.impl.interceptor.CommandInvoker$1.run(CommandInvoker.java:75)
at org.flowable.engine.impl.interceptor.CommandInvoker.executeOperation(CommandInvoker.java:199)
at org.flowable.engine.impl.interceptor.CommandInvoker.executeOperations(CommandInvoker.java:128)
at org.flowable.engine.impl.interceptor.CommandInvoker.execute(CommandInvoker.java:80)
at org.flowable.engine.impl.interceptor.BpmnOverrideContextInterceptor.execute(BpmnOverrideContextInterceptor.java:26)
at org.flowable.common.engine.impl.interceptor.TransactionContextInterceptor.execute(TransactionContextInterceptor.java:53)
at org.flowable.common.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:105)
at org.flowable.common.spring.SpringTransactionInterceptor.lambda$execute$0(SpringTransactionInterceptor.java:57)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
at org.flowable.common.spring.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:57)
at org.flowable.common.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:30)
at org.flowable.common.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:56)
at org.flowable.common.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:51)
at org.flowable.engine.impl.RepositoryServiceImpl.deploy(RepositoryServiceImpl.java:99)
at org.flowable.engine.impl.repository.DeploymentBuilderImpl.deploy(DeploymentBuilderImpl.java:206)
at com.example.runtime.process.service.ProcessDeployService.deployProcess(ProcessDeployService.java:140)
at com.example.runtime.process.service.ProcessDeployService.deployProcesses(ProcessDeployService.java:112)
at com.example.runtime.process.service.ProcessDeployService.deployAndCacheProcesses(ProcessDeployService.java:81)
at com.example.runtime.process.config.FlowableAutoConfiguration.buildAndStartEngine(FlowableAutoConfiguration.java:247)
at com.example.runtime.process.config.FlowableAutoConfiguration.initialize(FlowableAutoConfiguration.java:112)
at org.springframework.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:383)
at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:255)
at org.springframework.context.event.ApplicationListenerMethodAdapter.onApplicationEvent(ApplicationListenerMethodAdapter.java:174)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:185)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:178)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:156)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:455)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:388)
at org.springframework.boot.context.event.EventPublishingRunListener.ready(EventPublishingRunListener.java:109)
at org.springframework.boot.SpringApplicationRunListeners.lambda$ready$6(SpringApplicationRunListeners.java:80)
at org.springframework.boot.SpringApplicationRunListeners.ready(SpringApplicationRunListeners.java:80)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:332)
at com.example.runtime.Application.main(Application.java:27)
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:106)
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64)
at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40)

Caused by: org.xml.sax.SAXParseException; systemId: jar:file:/D:/workspace/流程/runtime/.runtime.jar.exploded/BOOT-INF/lib/flowable-bpmn-converter-7.2.0.jar!/org/flowable/impl/bpmn/parser/BPMN20.xsd; lineNumber: 15; columnNumber: 70; src-resolve: Cannot resolve the name 'extension' to a(n) 'element declaration' component.
at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:135)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:396)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaErr(XSDHandler.java:4254)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaError(XSDHandler.java:4237)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.getGlobalDecl(XSDHandler.java:1791)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDElementTraverser.traverseLocal(XSDElementTraverser.java:170)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.traverseLocalElements(XSDHandler.java:3707)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:543)
at java.xml/com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory.newSchema(XMLSchemaFactory.java:281)
at java.xml/javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:612)
at java.xml/javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:644)
at org.flowable.bpmn.converter.BpmnXMLConverter.createSchema(BpmnXMLConverter.java:252)
at org.flowable.bpmn.converter.BpmnXMLConverter.validateModel(BpmnXMLConverter.java:231)
at org.flowable.bpmn.converter.BpmnXMLConverter.convertToBpmnModel(BpmnXMLConverter.java:283)
... 51 common frames omitted

Minimal Reproduction

The following minimal Spring Boot application uses Flowable in the normal way. It does not manually load BPMN20.xsd and does not configure a custom classloader. It only calls Flowable's default BPMN XML conversion with schema validation enabled.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.12</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>flowable-non-ascii-classpath-repro</artifactId>
    <version>1.0.0</version>

    <properties>
        <java.version>17</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-bpmn-converter</artifactId>
            <version>7.2.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

src/main/java/com/example/repro/FlowableNonAsciiClasspathReproApplication.java

package com.example.repro;

import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.common.engine.api.io.InputStreamProvider;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

@SpringBootApplication
public class FlowableNonAsciiClasspathReproApplication implements CommandLineRunner {

    private static final String BPMN_XML = """
            <?xml version="1.0" encoding="UTF-8"?>
            <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
                         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                         targetNamespace="http://example.com/process">
              <process id="process1" isExecutable="true">
                <startEvent id="start" />
              </process>
            </definitions>
            """;

    public static void main(String[] args) {
        SpringApplication.run(FlowableNonAsciiClasspathReproApplication.class, args);
    }

    @Override
    public void run(String... args) {
        BpmnXMLConverter converter = new BpmnXMLConverter();
        converter.convertToBpmnModel(new BpmnInputStreamProvider(), true, false);

        System.out.println("Flowable BPMN XML conversion succeeded");
    }

    private static class BpmnInputStreamProvider implements InputStreamProvider {
        @Override
        public InputStream getInputStream() {
            return new ByteArrayInputStream(BPMN_XML.getBytes(StandardCharsets.UTF_8));
        }
    }
}

reproduce.ps1

param(
    [string]$WorkDir = "$env:TEMP\flowable-repro-流程"
)

$ErrorActionPreference = "Stop"

mvn -DskipTests package
if ($LASTEXITCODE -ne 0) {
    exit $LASTEXITCODE
}

Remove-Item -Recurse -Force $WorkDir -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Path $WorkDir | Out-Null

Copy-Item ".\target\flowable-non-ascii-classpath-repro-1.0.0.jar" "$WorkDir\app.jar"

Push-Location $WorkDir
try {
    jar -xf app.jar
    if ($LASTEXITCODE -ne 0) {
        exit $LASTEXITCODE
    }

    java org.springframework.boot.loader.launch.JarLauncher
    exit $LASTEXITCODE
}
finally {
    Pop-Location
}

How to Run the Reproduction

From the reproduction project directory:

pwsh -NoProfile -File .\reproduce.ps1

The script creates an unpacked runtime layout like:

%TEMP%\flowable-repro-流程\BOOT-INF\classes
%TEMP%\flowable-repro-流程\BOOT-INF\lib\flowable-bpmn-converter-7.2.0.jar

Reproduction Output

Starting FlowableNonAsciiClasspathReproApplication v1.0.0 using Java 21.0.6
(C:\Users\<user>\AppData\Local\Temp\flowable-repro-流程\BOOT-INF\classes started by <user>
in C:\Users\<user>\AppData\Local\Temp\flowable-repro-流程)

org.flowable.bpmn.exceptions.XMLException: src-resolve: Cannot resolve the name 'extension' to a(n) 'element declaration' component.
    at org.flowable.bpmn.converter.BpmnXMLConverter.convertToBpmnModel(BpmnXMLConverter.java:292) ~[flowable-bpmn-converter-7.2.0.jar:7.2.0]
    at org.flowable.bpmn.converter.BpmnXMLConverter.convertToBpmnModel(BpmnXMLConverter.java:262) ~[flowable-bpmn-converter-7.2.0.jar:7.2.0]
    at com.example.repro.FlowableNonAsciiClasspathReproApplication.run(FlowableNonAsciiClasspathReproApplication.java:34) ~[classes/:1.0.0]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) ~[spring-boot-3.2.12.jar:3.2.12]
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:774) ~[spring-boot-3.2.12.jar:3.2.12]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:342) ~[spring-boot-3.2.12.jar:3.2.12]
    at com.example.repro.FlowableNonAsciiClasspathReproApplication.main(FlowableNonAsciiClasspathReproApplication.java:28) ~[classes/:1.0.0]
    at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:102) ~[flowable-repro-%e6%b5%81%e7%a8%8b/:na]
    at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64) ~[flowable-repro-%e6%b5%81%e7%a8%8b/:na]
    at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40) ~[flowable-repro-%e6%b5%81%e7%a8%8b/:na]
Caused by: org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'extension' to a(n) 'element declaration' component.
    at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204) ~[na:na]
    at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:135) ~[na:na]
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:396) ~[na:na]
    at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaErr(XSDHandler.java:4254) ~[na:na]
    at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaError(XSDHandler.java:4237) ~[na:na]
    at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.getGlobalDecl(XSDHandler.java:1791) ~[na:na]
    at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDElementTraverser.traverseLocal(XSDElementTraverser.java:170) ~[na:na]
    at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.traverseLocalElements(XSDHandler.java:3707) ~[na:na]
    at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.parseSchema(XSDHandler.java:666) ~[na:na]
    at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadSchema(XMLSchemaLoader.java:618) ~[na:na]
    at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:577) ~[na:na]
    at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:543) ~[na:na]
    at java.xml/com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory.newSchema(XMLSchemaFactory.java:281) ~[na:na]
    at java.xml/javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:612) ~[na:na]
    at java.xml/javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:644) ~[na:na]
    at org.flowable.bpmn.converter.BpmnXMLConverter.createSchema(BpmnXMLConverter.java:252) ~[flowable-bpmn-converter-7.2.0.jar:7.2.0]
    at org.flowable.bpmn.converter.BpmnXMLConverter.validateModel(BpmnXMLConverter.java:231) ~[flowable-bpmn-converter-7.2.0.jar:7.2.0]
    at org.flowable.bpmn.converter.BpmnXMLConverter.convertToBpmnModel(BpmnXMLConverter.java:283) ~[flowable-bpmn-converter-7.2.0.jar:7.2.0]
    ... 27 common frames omitted

Observed Behavior

When the Flowable jar is loaded from an unpacked Spring Boot classpath under a non-ASCII directory, Flowable's default BPMN XML conversion fails during schema validation.

The failure occurs inside:

org.flowable.bpmn.converter.BpmnXMLConverter.createSchema
org.flowable.bpmn.converter.BpmnXMLConverter.validateModel
org.flowable.bpmn.converter.BpmnXMLConverter.convertToBpmnModel

Expected Behavior

Flowable should be able to load and validate its built-in BPMN schema resources from classpath jars even when the jar path contains non-ASCII characters.

Non-ASCII classpath locations are valid in localized user environments and should not prevent BPMN deployment or schema validation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions