This guide helps you diagnose and resolve common issues with the ClaudeCode Elixir SDK.
- Installation Issues
- Authentication Problems
- CLI Integration Issues
- Session Management
- Streaming Problems
- Performance Issues
- Error Reference
Problem: mix deps.get fails to find the ClaudeCode package.
Solution:
# Make sure you're using the correct package name and version
def deps do
[
{:claude_code, "~> 0.35"}
]
endIf using a pre-release version:
def deps do
[
{:claude_code, github: "guess/claude_code", branch: "main"}
]
endProblem: ClaudeCode fails to compile with dependency errors.
Common causes:
- Incompatible Elixir/OTP versions
- Missing required dependencies
Solution:
# Check your Elixir version (requires 1.18+)
elixir --version
# Clean and reinstall dependencies
mix deps.clean --all
mix deps.get
mix compileProblem: Getting authentication errors when starting a session.
Error message:
{:error, {:claude_error, "Authentication failed"}}
Solutions:
-
Check your API key:
echo $ANTHROPIC_API_KEY
-
Verify the key format:
# Should start with 'sk-ant-' export ANTHROPIC_API_KEY="sk-ant-your-key-here"
-
Test with the Claude CLI directly:
claude --version echo "Hello" | claude
-
Use a different environment variable:
{:ok, session} = ClaudeCode.start_link( api_key: System.get_env("MY_CLAUDE_KEY") )
Problem: Session fails to start with missing API key.
Error message:
{:error, "API key is required"}
Solutions:
-
Set the environment variable:
export ANTHROPIC_API_KEY="your-key-here"
-
Pass the key directly:
{:ok, session} = ClaudeCode.start_link( api_key: "your-key-here" # Not recommended for production )
-
Use application config:
# config/config.exs config :claude_code, api_key: System.get_env("ANTHROPIC_API_KEY")
Problem: ClaudeCode can't find the Claude CLI binary.
Error message:
{:error, {:cli_not_found, "Claude CLI not found."}}
Solutions:
-
Use the default bundled mode (auto-installs to priv/bin/):
mix claude_code.install
With the default
cli_path: :bundled, the SDK auto-installs the CLI on first use. If auto-install fails (e.g., no network), pre-install with the mix task. -
Use a global installation:
# Install the CLI system-wide curl -fsSL https://claude.ai/install.sh | bash # Then configure the SDK to use it config :claude_code, cli_path: :global
-
Use an explicit path:
config :claude_code, cli_path: "/path/to/claude"
-
Check the resolved path:
mix claude_code.path
Problem: ClaudeCode doesn't work with your Claude CLI version.
Solution:
# Check CLI version
claude --version
# Update to latest version
# Follow update instructions at claude.ai/codeSupported CLI versions: 0.8.0+
Problem: CLI subprocess hangs or doesn't respond.
Common causes:
- CLI waiting for input
- Network connectivity issues
- CLI process stuck
Solutions:
-
Check timeout settings:
{:ok, session} = ClaudeCode.start_link( api_key: "...", timeout: 300_000 # 5 minutes )
-
Test CLI directly:
echo "Hello" | claude --print
-
Check network connectivity:
curl -I https://api.anthropic.com
Problem: Session GenServer crashes or stops responding.
Debugging steps:
-
Check session status:
ClaudeCode.Session.alive?(session)
-
Use supervision (manual setup required):
# ClaudeCode doesn't provide built-in child_spec # You need to create a wrapper or use a simple supervisor defmodule MyApp.ClaudeSupervisor do use Supervisor def start_link(opts) do Supervisor.start_link(__MODULE__, opts, name: __MODULE__) end def init(opts) do children = [ {ClaudeCode, [api_key: "...", name: :claude_session]} ] Supervisor.init(children, strategy: :one_for_one) end end
Problem: Session maintains incorrect conversation context.
Solutions:
-
Clear session state:
ClaudeCode.Session.clear(session)
-
Restart session:
ClaudeCode.stop(session) {:ok, new_session} = ClaudeCode.start_link(opts)
-
Use fresh sessions for unrelated queries:
# For isolated queries, use the one-off query/2 {:ok, result} = ClaudeCode.query(prompt) # Or manually manage a session {:ok, temp_session} = ClaudeCode.start_link() temp_session |> ClaudeCode.stream(prompt) |> Stream.run() ClaudeCode.stop(temp_session)
Problem: Streaming query returns empty stream or never yields data.
Debugging:
-
Test with one-off query first:
case ClaudeCode.query(prompt) do {:ok, response} -> IO.puts("One-off works: #{response}") error -> IO.puts("One-off error: #{inspect(error)}") end
-
Check stream consumption:
# Force stream evaluation session |> ClaudeCode.stream(prompt) |> Enum.to_list() |> IO.inspect()
-
Use stream utilities:
session |> ClaudeCode.stream(prompt) |> ClaudeCode.Stream.text_content() |> Enum.each(&IO.write/1)
Problem: Stream starts but stops producing data.
Solutions:
-
Add timeouts:
session |> ClaudeCode.stream(prompt, timeout: 120_000) |> Stream.take_while(fn _ -> true end) |> Enum.to_list()
-
Use stream debugging:
session |> ClaudeCode.stream(prompt) |> Stream.each(fn msg -> IO.inspect(msg, label: "Stream message") end) |> ClaudeCode.Stream.text_content() |> Enum.to_list()
Problem: Streaming large responses causes memory issues.
Solutions:
-
Process chunks immediately:
session |> ClaudeCode.stream(prompt) |> ClaudeCode.Stream.text_content() |> Stream.each(&IO.write/1) # Don't accumulate |> Stream.run()
-
Use collect for structured results:
# When you need the full response organized summary = session |> ClaudeCode.stream(prompt) |> ClaudeCode.Stream.collect() # Process the collected data IO.puts(summary.result)
Problem: Queries take too long to respond.
Optimization strategies:
-
Use appropriate models:
# For simple tasks, use faster models {:ok, session} = ClaudeCode.start_link( api_key: "...", model: "claude-3-haiku-20240307" # Faster model )
-
Optimize prompts:
# Be specific and concise prompt = "Briefly explain GenServers in 2 paragraphs."
-
Use streaming for responsiveness:
# User sees response immediately session |> ClaudeCode.stream(prompt) |> ClaudeCode.Stream.text_content() |> Enum.each(&IO.write/1)
Problem: ClaudeCode uses too much memory.
Solutions:
-
Limit concurrent sessions:
# Limit the number of concurrent sessions manually # (No built-in session pooling - you need to implement this) max_sessions = System.schedulers_online() # Example: Use Task.async_stream with max_concurrency
-
Clean up sessions:
# Always stop sessions when done ClaudeCode.stop(session)
-
Monitor memory usage:
:erlang.memory()
Problem: Too many concurrent requests to Claude API.
Error message:
{:error, {:claude_error, "Rate limit exceeded"}}
Solutions:
-
Implement backoff:
defp query_with_backoff(session, prompt, retries \\ 3) do try do result = session |> ClaudeCode.stream(prompt) |> ClaudeCode.Stream.text_content() |> Enum.join() {:ok, result} catch error when retries > 0 -> :timer.sleep(2000) # Wait 2 seconds query_with_backoff(session, prompt, retries - 1) error -> {:error, error} end end
-
Use fewer concurrent sessions:
# Limit parallelism Task.async_stream(tasks, &process_task/1, max_concurrency: 2)
{:error, {:cli_not_found, message}} # Claude CLI not installed
{:error, {:cli_exit, exit_code}} # CLI crashed or failed
{:error, {:port_closed, reason}} # Communication failure{:error, {:claude_error, "Invalid API key"}}
{:error, {:claude_error, "Authentication failed"}}
{:error, {:claude_error, "Rate limit exceeded"}}{:error, :timeout} # Query timed out
{:error, :session_not_found} # Session doesn't exist
{:error, {:invalid_options, details}} # Bad configuration{:stream_error, reason} # Generic stream error
{:stream_timeout, request_ref} # Stream timed out
{:stream_init_error, reason} # Failed to start stream# Check if Claude CLI is available
System.cmd("which", ["claude"])
# Test CLI directly
System.cmd("claude", ["--version"])
# Check environment
System.get_env("ANTHROPIC_API_KEY")
# Test network connectivity
System.cmd("curl", ["-I", "https://api.anthropic.com"])# Add to config/config.exs
config :logger, :console,
level: :debug,
format: "$time $metadata[$level] $message\n"
# Or in IEx
Logger.configure(level: :debug)# Memory usage
:erlang.memory()
# Process info
Process.info(session_pid)
# System info
:erlang.system_info(:process_count)If you're still having issues:
- Check the logs - Enable debug logging to see what's happening
- Test components individually - CLI, network, authentication
- Create a minimal reproduction - Isolate the problem
- Check GitHub issues - Someone might have seen this before
- Open an issue - Include logs, environment details, and reproduction steps
# Paste this into IEx to reproduce the issue
alias ClaudeCode
# Your environment
IO.puts("Elixir: #{System.version()}")
IO.puts("OTP: #{System.otp_release()}")
case System.cmd("claude", ["--version"]) do
{output, 0} -> IO.puts("Claude CLI: #{String.trim(output)}")
{error, code} -> IO.puts("Claude CLI error: #{error} (exit: #{code})")
end
# Your code that demonstrates the problem
{:ok, session} = ClaudeCode.start_link(
api_key: System.get_env("ANTHROPIC_API_KEY")
)
# The failing operation
result =
session
|> ClaudeCode.stream("Hello")
|> Enum.to_list()
IO.inspect(result, label: "Result")
ClaudeCode.stop(session)Include this output when reporting issues for faster resolution.