Troubleshooting and FAQ
Build and Gradle
Section titled “Build and Gradle”Gradle can’t find a JDK 17
Section titled “Gradle can’t find a JDK 17”Arc’s Gradle plugin and generated code target JDK 17 exactly. Make a JDK 17 installation the active
JAVA_HOME/PATH before running ./gradlew:
export JAVA_HOME=/opt/homebrew/opt/openjdk@17 # path varies by OS and installerexport PATH="$JAVA_HOME/bin:$PATH"java -versionThe sample run.sh scripts do this detection automatically.
generateArcProxies fails with “Unsupported Arc artifact manifest format N; expected M”
Section titled “generateArcProxies fails with “Unsupported Arc artifact manifest format N; expected M””A classpath mixes manifests produced by different Arc KSP versions. Rebuild every module that
contributes an Arc manifest — both the producer (the module declaring @Command/@ReadModel types)
and every consumer (the module calling generateArcProxies against those types) — with the same Arc
version. See Configuration reference for the manifest format and what
changes between versions.
Startup fails with “Arc endpoint-options mismatch”
Section titled “Startup fails with “Arc endpoint-options mismatch””The Gradle plugin’s build-time route settings (cratisArc.endpoints.*) disagree with the runtime
properties (cratis.arc.endpoints.*). The error names the exact setting and both values — align
them in build.gradle.kts and application.properties. See
Configure generation.
./gradlew checkSpringBoundary fails
Section titled “./gradlew checkSpringBoundary fails”Source’s compiled artifacts, metadata, and json packages — and every local type they
transitively reference — must stay Spring-free. This check exists to keep the KSP processor and
Gradle plugin usable without pulling Spring onto the compiler/build-tool classpath. Move the
offending dependency behind an integration module instead of adding it to Source.
Compile-time (ARCKSP) errors
Section titled “Compile-time (ARCKSP) errors”Every KSP diagnostic carries a stable code and an actionable message, for example:
[ARCKSP0101] Command 'CreateTask' must be a public top-level class.The complete catalog, with severity and meaning, is in CodeGeneration/KSP/DIAGNOSTICS.md at the
repository root. The most common ones:
| Code | Usual cause |
|---|---|
ARCKSP0100 | A class looks command-shaped (has a public handle) but is missing @Command |
ARCKSP0101 / ARCKSP0200 | A @Command/@ReadModel class is not a public top-level declaration |
ARCKSP0102 / ARCKSP0201 | handle or a query method is not public, or is on a private/internal companion |
ARCKSP0106 | Two members both resolve as the command key |
ARCKSP0108 | @AllowAnonymous combined with @Authorize/@Roles, on the same target or across class and operation |
ARCKSP0109 | An aggregate command response leaves more than one possible client-visible leaf |
ARCKSP0300 | A computed or read-only Kotlin property reached through command input; use a backed property or a separate output model |
ARCKSP0301 | A Jakarta/Hibernate constraint cannot be represented as a client-side rule |
See Annotation reference for the exact contract each annotation enforces.
Runtime behavior
Section titled “Runtime behavior”A command fails with reason: "rule" and reasonDetail: "commandKey"
Section titled “A command fails with reason: "rule" and reasonDetail: "commandKey"”The command needs a Chronicle event response but has no usable @CommandKey. Declare one backed by
String, UUID, a number, or a concept wrapping one of those. See
Return an event.
An observable query returns HTTP 202 with no data
Section titled “An observable query returns HTTP 202 with no data”The query’s source is a cold Flow or Flow.Publisher that has not produced a value yet. Either
back the query with a MutableStateFlow/SubmissionPublisher (which always has a current value), or
request waitForFirstResult=true on the HTTP snapshot route. See
Consume an observable query.
The Chronicle integration fails at startup with Could not provision event store ... (authorized=false, ...)
Section titled “The Chronicle integration fails at startup with Could not provision event store ... (authorized=false, ...)”The connected kernel is older than 18.4.0. Kernels 18.3.1 and earlier omit the IsAuthorized field
from gRPC responses when a request was authorized, which a JVM proto3 client decodes as false.
Upgrade to Chronicle kernel 18.4.0 or newer — the pinned development image is
cratis/chronicle:18.4.0-development. See
Add Chronicle optionally.
A generated TypeScript client rejects a request with a malformed-request error
Section titled “A generated TypeScript client rejects a request with a malformed-request error”Check for a reserved key (__proto__, prototype, constructor) in a map property, a QUERY body
field outside arguments/paging/sorting, or a client argument name that collides with another
after case folding — GET and QUERY match argument names case-insensitively. See the
HTTP contract reference.
Which sample should I run to see a specific behavior?
Section titled “Which sample should I run to see a specific behavior?”- No external dependencies, plain commands and queries:
Samples/Kotlin/SpringBootorSamples/Java/SpringBoot. - Chronicle events, concurrency, and tenant-scoped read models:
Samples/Kotlin/ChronicleSpringBootorSamples/Java/ChronicleSpringBoot.
Each has a run.sh — see Running the samples.
“Is this feature really implemented?”
Section titled ““Is this feature really implemented?””Every implementation claim in this documentation is backed by a test, contract test, or runnable sample named in the feature parity reference. If a guide describes a behavior and you want to know exactly what proves it — or whether it matches Arc on .NET — that document is the source of truth, not this page or the README.
Still stuck?
Section titled “Still stuck?”Open a GitHub issue with the exact error message, the Arc version, and a minimal reproduction. The Cratis Discord is the place for open-ended questions.