TramAI - governed AI workflows for Java and Kotlin

Troubleshooting

This page collates common errors from across the TramAI guides into a single reference.


0.6.0 Failure Signatures

Five failures are new or newly explicit in 0.6.0. If a deployment that used to start now refuses to, or an error type changed, start here.

Sovereign profile: tramai.sovereign.enabled=false is rejected

Symptom: the application fails to start with

tramai.sovereign.enabled=false is not supported: tramai.profile is the sole runtime selector.
Remove tramai.sovereign.enabled or set it to true; to run the standard runtime select
tramai.profile=standard (or omit it).

Cause: the property is a leftover compatibility switch from the 0.4.x/0.5.x separate starter. tramai.profile is the only selector in 0.6.0, so the flag has no meaning.

Fix: delete tramai.sovereign.enabled from your configuration. To run the standard runtime, set tramai.profile: standard (or remove the property entirely).

Sovereign profile: allowlist, zone, or route validation fails at startup

Symptom: startup fails with tramai-sovereign-spring-* codes — for example tramai-sovereign-spring-missing-allowed-models, tramai-sovereign-spring-provider-zone-missing, tramai-sovereign-spring-model-route-unknown-provider, or tramai-sovereign-spring-invalid-provider-zone.

Cause: the tramai.sovereign.* block is incomplete. The rules are: non-empty allowed-models and allowed-providers; every allowed provider needs a provider-zones entry using a real ProviderTrustZone value; every allowed model needs a models route; every route target must be an allowed provider.

Fix: complete the allowlist block. The full rule table, including the embedded-path codes (offline-profile-non-local-provider-rejected, artifact-digest-required-for-local-model, artifact-verification-not-configured), is in the Sovereign Runtime Quickstart. A profile value outside standard / sovereign fails with Unsupported tramai.profile '<value>'. Supported values: standard, sovereign.

Stores: IllegalStateException where SQLException used to be

Symptom: a catch block for java.sql.SQLException no longer fires; the caller sees IllegalStateException with a generic message.

Cause: this is intended. JDBC stores map driver and SQL failures to IllegalStateException with redacted details, and never leak SQL text, table names, connection strings, or vendor diagnostics.

Fix: catch IllegalStateException (or RuntimeException). Do not attempt to recover the raw SQLException — it is deliberately gone. Coroutine CancellationException and TramAI domain exceptions still pass through unwrapped, so keep distinguishing those from storage failures.

Cancellation is never wrapped

Symptom: a cancelled request is retried, counted as a provider failure, triggers a fallback, or surfaces as some other exception type.

Cause: application code swallowed it. TramAI itself preserves and propagates CancellationException on every path.

Fix: in every catch (e: Exception) block around TramAI calls, call e.rethrowIfCancellation() (from dev.tramai.core.coroutines) before handling the error. Never log-and-continue on cancellation, and never translate it into a domain error.

Image retrieval is rejected as unsafe

Symptom: IllegalArgumentException from multimodal image retrieval — unsupported outbound scheme, outbound URI must not contain user info, outbound host is restricted, outbound host resolves to a restricted address, failed to resolve outbound host, or Image download exceeds maximum size.

Cause: the SSRF admission boundary. Non-HTTP(S) schemes, embedded credentials, localhost, and loopback/link-local/private/CGNAT/ULA addresses are refused before any connection is made, redirect targets are re-validated, and the payload is capped.

Fix: fetch images from public HTTP(S) endpoints. If you genuinely need a private destination (an internal asset store, for example), do not weaken the check in application code — download through your own allowlisted path and hand TramAI the bytes as an ImagePart. See Production Hardening & Security.


Model Not Found

Symptom: ModelNotFoundException: Model 'xxx' is not mapped to any provider.

Cause: An operation references a model name that has not been mapped to a provider in your TramAI engine configuration.

Solution: Ensure every model is explicitly mapped:

val tramai = Tramai {
    provider(OpenAiProvider(...), name = "openai")
    model("gpt-4o", "openai") // required mapping
}

Structured Output Parsing Fails

Symptom: StructuredOutputException: Failed to parse AI response into type 'YourType'. Logs show invalid JSON or wrong schema.

Cause: The model failed to follow the requested output format. Common with smaller models.

Solutions:

  1. Use a more capable model (gpt-4o, claude-sonnet-4-20250514)
  2. Add explicit format instructions in your @Operation(prompt = "...")
  3. Check that retries are enabled — TramAI feeds validation errors back to the model on retry
  4. Default retries: 2. Configurable via @Operation(maxRetries = N)

Provider Authentication Failures

Symptom: ProviderException: Unauthorized (401), AuthenticationException, or similar auth error.

Causes: Missing, invalid, expired, or rotated API key. Environment variable not picked up.

Solutions:

  • Verify the environment variable: echo $OPENAI_API_KEY
  • In Spring Boot, check application.yaml:
    tramai:
      providers:
        openai:
          api-key: ${OPENAI_API_KEY}
    
  • Use SecretValueResolver for secure credential management
  • Check that the API key has not been rotated or revoked at the provider console
  • For Azure OpenAI, verify the endpoint URL and API version are correct

Provider Timeout Errors

Symptom: ProviderException: Request timed out, java.net.SocketTimeoutException, or Read timed out.

Causes: Network latency, provider overload, or tight client timeouts.

Solutions:

  • Increase the HTTP client timeout in your provider configuration
  • Check network connectivity between your application and the provider endpoint
  • Verify proxy/firewall settings if using a corporate network
  • For Ollama, ensure the service is running and accessible: curl http://localhost:11434/api/tags
  • Consider circuit breaker and retry configuration to handle transient timeouts

Provider Rate Limit Errors

Symptom: ProviderException: 429 Too Many Requests, RateLimitError, or Retry-After headers in logs.

Causes: Exceeding the provider's API rate limit or token-per-minute quota.

Solutions:

  • Enable TramAI retry policy with exponential backoff (built into the engine):
    retryPolicy(
        RetryPolicySettings(
            maxRetryAfterMillis = 20_000,
            jitterRatio = 0.1,
        ),
    )
    
  • Reduce concurrent operation throughput
  • Increase your provider plan tier if rate limits are consistently hit
  • Implement a token-bucket rate limiter on your side for predictable usage

Spring Bean Injection Fails

Symptom: NoSuchBeanDefinitionException: No qualifying bean of type 'YourAiService' available.

Causes and solutions:

  1. Ensure @AiService is on the interface, not an implementation class
  2. Check that the interface is in a package scanned by Spring (under @SpringBootApplication or explicit @ComponentScan)
  3. Verify a TramAI Spring runtime is on the classpath: tramai-spring-boot-starter (Spring Boot auto-configuration) or tramai-spring (plain Spring context)
  4. Verify at least one provider is available — a tramai-spring-provider-* adapter with its properties, or a ModelProvider bean. Under the sovereign profile, resolving zero providers fails startup with tramai.profile=sovereign requires at least one model provider

ClassNotFound / NoClassDefFoundError

Symptom: java.lang.NoClassDefFoundError: dev/tramai/core/... at runtime.

Cause: Missing optional module dependency.

Solution: Ensure all required modules are in your build file:

dependencies {
    implementation(platform("dev.tramai:tramai-bom:0.6.0"))
    implementation("dev.tramai:tramai-standalone")
    implementation("dev.tramai:tramai-openai")
}

TramAI modules are opt-in. You need:

  • tramai-standalone (non-Spring runtime) or tramai-spring-boot-starter (Spring Boot) as the runtime entry point — adding the BOM first means no individual version pins
  • at least one provider module (tramai-openai, tramai-anthropic, tramai-ollama, or a tramai-spring-provider-* adapter for Spring)
  • tramai-structured is pulled transitively by standalone/spring
  • optional published modules: tramai-observability, tramai-orchestration, tramai-scheduler, tramai-platform, tramai-sovereign, tramai-security

tramai-server, tramai-dashboard, and tramai-mcp are internal to the TramAI repository — they are not published artifacts, so a NoClassDefFoundError naming them means the code path belongs to a different deployment shape.


Native Image Build Fails

Symptom: com.oracle.svm.core.jdk.proxy.DynamicProxyProxyCreationError or missing proxy at runtime.

Cause: @AiService interface not registered in GraalVM proxy-config.json.

Solution: Generate and include proxy metadata:

NativeImageProxyConfig.write(
    outputPath = Path.of("src/main/resources/META-INF/native-image/.../proxy-config.json"),
    InvoiceAnalyzer::class,
)

See Native Image for the full workflow.


Native Image: Reflection Errors

Symptom: java.lang.ClassNotFoundException or reflective access errors in native image.

Cause: TramAI or provider libraries need reflection hints not included in the image.

Common fixes:

  • Add --enable-url-protocols=https if using HTTPS providers
  • Add Jackson reflection hints for your data classes
  • Add -H:ReflectionConfigurationFiles=... for provider-specific reflection
  • Test with -H:+ReportUnsupportedElementsAtRuntime for diagnostics

Spring Boot Configuration Issues

Symptom: TramAI beans are not configured as expected, or auto-configuration fails silently.

Common causes:

SymptomLikely causeFix
Wrong model usedProperty typo in application.yamlCheck tramai.models.* keys
Default provider not setMissing tramai.default-providerAdd tramai.default-provider: openai
Provider not foundMissing provider section, missing adapter dependency, or no API keyCheck tramai.providers.* and the tramai-spring-provider-* dependency
DLP not workingMultiple DlpInterceptor beansDefine exactly one
Observability missingOTel not on classpathAdd tramai-observability dep
Startup rejects the profileUnsupported tramai.profile valueUse standard or sovereign
Sovereign profile fails validationIncomplete tramai.sovereign.* allowlist blockSee the 0.6.0 failure signatures

Provider-Specific Errors

ProviderCommon ErrorCauseFix
OpenAI429 Too Many RequestsRate limit exceededIncrease retry budget or reduce concurrency
Anthropic529 OverloadedAnthropic server overloadRetry with backoff — built into engine
OllamaConnection refusedOllama not running locallyStart ollama serve or check base URL
Azure OpenAI401 UnauthorizedWrong endpoint or API versionVerify endpoint URL and API version
BedrockAccessDeniedExceptionMissing AWS IAM permissionsCheck role policy for Bedrock access

Builder Configuration Mistakes

Common mistakes when using the Tramai { ... } builder DSL.

SymptomCauseFix
IllegalArgumentException: Provider 'xxx' not foundModel references a provider name that was never registeredCheck provider(...) call — the name parameter must match the model mapping
IllegalStateException: No default providerNo provider was marked default = true but the model has no explicit provider routeAdd default = true to one provider or always qualify model names
MissingMethodException: No signature of methodDSL block references a method not available in the current moduleCheck that the required dependency (e.g. tramai-orchestration) is on the classpath
Model silently falls backfallbackModel was configured but the fallback provider is missing or misconfiguredVerify both primary and fallback providers are registered and healthy
NullPointerException in builderRequired property not set (e.g. API key is null)Ensure all required properties are provided before passing to the builder

Orchestration Errors

Symptom: Resuming a suspended workflow throws PolicyViolationException with reason Workflow resume is not enabled and reason code workflow-resume-disabled.

Cause: PolicyConfiguration.allowWorkflowResume defaults to false. The engine evaluates every resume at the mandatory BEFORE_WORKFLOW_RESUME enforcement point, and the secure policy denies it unless the deployment opts in (DefaultPolicyEngine returns PolicyDecision.Deny("Workflow resume is not enabled", "workflow-resume-disabled")).

Fix: Opt in explicitly on the policy configuration your runtime uses:

val configuration = PolicyConfiguration.secure()
    .copy(allowWorkflowResume = true)

The sovereign profile sets this for you, but a hand-built DefaultPolicyEngine does not. Enabling resume does not relax the other enforcement points — tool exposure, execution, and result reinjection are still evaluated independently.


Scheduler Errors

SymptomCauseFix
Cron expression invalidWrong field count or valuesUse 5 or 6 fields; check minutes (0-59), hours (0-23)
Schedule never firesBusiness-hours filter activeCheck businessHoursOnly config
Misfired ticksWorker was downCheck misfireThreshold; increase if needed
Delay step never resumesScheduler polling not configuredEnsure ScheduledWorkflowTimer is running

Server Errors

SymptomCauseFix
400 Bad RequestInvalid workflow JSONCheck initial state matches workflow state type
401 UnauthorizedInvalid webhook signatureVerify tramai.server.webhooks.secret
413 Request Too LargeBody exceeds limitIncrease max-request-body-bytes
404 Not FoundUnknown workflow or run nameCheck workflow registration and run ID
SSE stream ends earlyRun reached terminal stateThis is expected — check status for result/error

Platform Errors

SymptomCauseFix
401 on platform endpointsMissing or invalid API keyProvide X-API-Key header
403 ForbiddenKey lacks required scopeCheck key scopes include run/read/admin
429 Too Many RequestsRate limit exceededCheck Retry-After header; increase key capacity
Plugin not foundJAR not in plugin directoryDrop JAR in tramai.platform.plugins.dir and enable via API
Team/project not foundTenant bootstrap pendingCreate team/project via repository or seed data

Logging Diagnostics

Enable DEBUG logging for TramAI internals to trace execution:

logging:
  level:
    dev.tramai: DEBUG

This reveals:

  • provider resolution decisions
  • retry attempt pacing
  • structured output parsing details
  • circuit breaker state transitions
  • interceptor execution order

Still Having Trouble?