Skip to content
tnsaiDocs
GitHub

Troubleshooting

A short, opinionated checklist for the failure modes that come up most often when picking up the framework. If your symptom isn't here, open a discussion, and the next pass updates this page.

"API key not configured" / credentials missing

LLM clients in tnsai-llm read their credentials from environment variables by default. Each provider expects its own variable:

ProviderVariable
AnthropicANTHROPIC_API_KEY
OpenAIOPENAI_API_KEY
GeminiGEMINI_API_KEY
Ollamanone (local daemon)
NVIDIA NIMNVIDIA_API_KEY
otherssee the provider list in tnsai-llm's README

Things to check, in order:

  1. The variable is set in the process where the JVM runs, not just in your shell. IDE run-configs and systemd units need their own env block.
  2. The variable name matches exactly (Anthropic is ANTHROPIC_API_KEY, not CLAUDE_API_KEY, and OpenAI rejects OPEN_AI_API_KEY).
  3. The key itself works against a curl test outside the framework, because accounts in trial mode sometimes have models the key can't reach.

If you want to bypass env-var lookup, every client builder accepts an explicit .apiKey(...) argument.

"Tools registered but the LLM never calls them"

Two common causes:

  • The LLM doesn't support function-calling. Local Ollama models and older OpenAI snapshots (gpt-3.5-turbo-0301) frequently lack tool-use. AgentBuilder.build() enforces this at build time via LLMCapabilityValidator (validator code AGENT-V003). If the validator says your LLM can't call tools, swap the model.
  • The tool isn't actually registered. Use agent.getToolsForLLM() after build to confirm the catalog the agent will send. If your @Tool-annotated method is missing, check that the POJO holding it is passed via AgentBuilder.toolPojos(...).

"LLM Capability Exception: streaming not supported"

BridgeLLMClient, the HTTP fallback client of the SCOP bridge, does not stream: calling streamChat() against it throws LLMCapabilityException. Two paths forward:

  • Install tnsai-llm and use the real provider client.
  • Call chat() (buffered single-shot) instead of streamChat().

"Context too long" / CONTEXT_TOO_LONG from a provider

Every provider has its own context window. TnsAI reports it as LLMException.ErrorType.CONTEXT_TOO_LONG, so you can branch on e.getErrorType() == LLMException.ErrorType.CONTEXT_TOO_LONG. Mitigations, in order of preference:

  1. Trim history before the call, with a consumer-side compaction step ahead of the request.
  2. Use a smaller-input model in the same family (Haiku/Mini variants typically have the same context as their larger sibling, but the response budget changes).
  3. If the prompt is dominated by RAG context, switch the retrieval strategy from top-K embedding to BM25 with a tighter K.

A test hangs waiting for a tool call

Check whether it's waiting on a virtual thread that never produces output. The default ToolCallFilter allows every call, but a filter that asks a person for approval waits until that person answers or its timeout runs out. The server's WebSocket approval filter waits 120 seconds and then rejects the call. See Tool call filters.

"Agent.chat() throws IllegalStateException"

The agent is already in the STOPPING / STOPPED / FAILED state. Calls to chat() after stop() raise rather than fail silently. Check agent.getState() before retrying, and only call stop() from cleanup paths.

  • FAQ: short answers to the most common starter questions.
  • Migration: which versions break the API.
  • Reliability guides: resilience patterns, error handling, retries.