Direct answer
Yes. The Ceylon runtime needs its module repository metadata at runtime, not just at build time. Each module ships as a .car archive that embeds the compiled module descriptor from module.ceylon, alongside a .sha1 checksum file in a modules/name/version tree. If production deploys loose JARs on a flat java -cp classpath, that metadata is invisible to the runtime, so imports declared in module.ceylon cannot be resolved and you see class-not-found, linkage, or version-mismatch failures.
When multiple versions of the same Ceylon module exist, the Ceylon runtime assigns each version its own class loader, so they can coexist. A module loads exactly the version it imported; consumers do not see non-shared imports. On a flattened classpath, only one version can win, producing undefined duplicate-class behavior.
Likely explanation versus confirmed facts
| Item | Status |
| Production failure is usually caused by launching compiled bytecode with java -cp instead of the Ceylon module runtime | Likely explanation |
| .car archives embed module descriptors; .sha1 files sit beside them in the repository | Confirmed Ceylon 1.x behavior |
| Ceylon runtime isolates module versions with separate class loaders | Confirmed Ceylon 1.x behavior |
| Flat classpath discards per-module versioning and visibility rules | Confirmed JVM classpath behavior |
Steps for this case
- On the build machine, run ceylon copy --with-dependencies module/version to assemble a self-contained repository, or copy the local modules tree.
- Deploy that repository to production so every modules/name/version/name-version.car file has a matching .sha1 file beside it.
- Launch with ceylon run module/version, pointing at the repository if it is not the default location.
- Do not add Ceylon .car files to a generic java -cp line; the flat classpath cannot enforce module boundaries.
Missing diagnostic detail
Confirm the exact production launch command: is the app started with ceylon run or with a hand-built java -cp command? Also record the Ceylon distribution version and JDK version. If production already uses the module runtime, the fault is likely a repository layout or checksum mismatch rather than classpath flattening.
Assumptions and uncertainty
- This answer targets Ceylon 1.x, approximately the 1.3.x line; development effectively ended around 2017, so no JVM-compatibility fixes should be expected.
- JDK 8 is the safest runtime target; JDK 9 and later may break the Ceylon runtime through the platform module system and removed internal APIs.
- Exact repository layout and metadata file names can vary between Ceylon 1.x releases; verify against the distribution used to build the project.
Verification
- Unzip a production .car and list its entries to confirm the embedded module descriptor.
- Compare the production modules tree against ceylon copy --with-dependencies output for the same module to spot missing versions or checksum files.
- Reproduce locally: run the module with ceylon run from a copied repository, then attempt a flat classpath launch, and compare the exact error messages.