504 lines
9.8 KiB
Markdown
504 lines
9.8 KiB
Markdown
# Top Errors & Solutions
|
|
|
|
Complete reference for common Claude Agent SDK errors and how to fix them.
|
|
|
|
---
|
|
|
|
## Error #1: CLI Not Found
|
|
|
|
### Error Message
|
|
```
|
|
"Claude Code CLI not installed"
|
|
```
|
|
|
|
### Why It Happens
|
|
The SDK requires Claude Code CLI to be installed globally, but it's not found in PATH.
|
|
|
|
### Solution
|
|
```bash
|
|
npm install -g @anthropic-ai/claude-code
|
|
```
|
|
|
|
Verify installation:
|
|
```bash
|
|
which claude-code
|
|
# Should output: /usr/local/bin/claude-code or similar
|
|
```
|
|
|
|
### Prevention
|
|
- Install CLI before using SDK
|
|
- Add to project setup documentation
|
|
- Check CLI availability in CI/CD
|
|
|
|
---
|
|
|
|
## Error #2: Authentication Failed
|
|
|
|
### Error Message
|
|
```
|
|
"Invalid API key"
|
|
"Authentication failed"
|
|
```
|
|
|
|
### Why It Happens
|
|
- ANTHROPIC_API_KEY environment variable not set
|
|
- API key is invalid or expired
|
|
- API key has wrong format
|
|
|
|
### Solution
|
|
```bash
|
|
# Set API key
|
|
export ANTHROPIC_API_KEY="sk-ant-..."
|
|
|
|
# Verify it's set
|
|
echo $ANTHROPIC_API_KEY
|
|
```
|
|
|
|
Get API key:
|
|
1. Visit https://console.anthropic.com/
|
|
2. Navigate to API Keys section
|
|
3. Create new key
|
|
4. Copy and save securely
|
|
|
|
### Prevention
|
|
- Use environment variables (never hardcode)
|
|
- Check key before running
|
|
- Add to .env.example template
|
|
- Document setup process
|
|
|
|
---
|
|
|
|
## Error #3: Permission Denied
|
|
|
|
### Error Message
|
|
```
|
|
"Tool use blocked"
|
|
"Permission denied for tool: Bash"
|
|
```
|
|
|
|
### Why It Happens
|
|
- Tool not in `allowedTools` array
|
|
- `permissionMode` is too restrictive
|
|
- Custom `canUseTool` callback denied execution
|
|
|
|
### Solution
|
|
```typescript
|
|
// Add tool to allowedTools
|
|
options: {
|
|
allowedTools: ["Read", "Write", "Edit", "Bash"] // Add needed tools
|
|
}
|
|
|
|
// Or use less restrictive permission mode
|
|
options: {
|
|
permissionMode: "acceptEdits" // Auto-approve edits
|
|
}
|
|
|
|
// Or check canUseTool logic
|
|
options: {
|
|
canUseTool: async (toolName, input) => {
|
|
console.log("Tool requested:", toolName); // Debug
|
|
return { behavior: "allow" };
|
|
}
|
|
}
|
|
```
|
|
|
|
### Prevention
|
|
- Set appropriate `allowedTools` from start
|
|
- Test permission logic thoroughly
|
|
- Use `permissionMode: "bypassPermissions"` in CI/CD
|
|
|
|
---
|
|
|
|
## Error #4: Context Length Exceeded
|
|
|
|
### Error Message
|
|
```
|
|
"Prompt too long"
|
|
"Context length exceeded"
|
|
"Too many tokens"
|
|
```
|
|
|
|
### Why It Happens
|
|
- Input prompt exceeds model's context window (200k tokens)
|
|
- Long conversation without pruning
|
|
- Large files in context
|
|
|
|
### Solution
|
|
SDK auto-compacts context, but you can:
|
|
|
|
```typescript
|
|
// Fork session to start fresh from a point
|
|
const forked = query({
|
|
prompt: "Continue with fresh context",
|
|
options: {
|
|
resume: sessionId,
|
|
forkSession: true // Start fresh
|
|
}
|
|
});
|
|
|
|
// Or reduce context
|
|
options: {
|
|
allowedTools: ["Read", "Grep"], // Limit tools
|
|
systemPrompt: "Keep responses concise."
|
|
}
|
|
```
|
|
|
|
### Prevention
|
|
- Use session forking for long tasks
|
|
- Keep prompts focused
|
|
- Don't load unnecessary files
|
|
- Monitor context usage
|
|
|
|
---
|
|
|
|
## Error #5: Tool Execution Timeout
|
|
|
|
### Error Message
|
|
```
|
|
"Tool did not respond"
|
|
"Tool execution timeout"
|
|
```
|
|
|
|
### Why It Happens
|
|
- Tool takes too long (>5 minutes default)
|
|
- Infinite loop in tool implementation
|
|
- Network timeout for external tools
|
|
|
|
### Solution
|
|
|
|
For custom tools:
|
|
```typescript
|
|
tool("long_task", "Description", schema, async (args) => {
|
|
// Add timeout
|
|
const timeout = 60000; // 1 minute
|
|
const promise = performLongTask(args);
|
|
const result = await Promise.race([
|
|
promise,
|
|
new Promise((_, reject) =>
|
|
setTimeout(() => reject(new Error('Timeout')), timeout)
|
|
)
|
|
]);
|
|
return { content: [{ type: "text", text: result }] };
|
|
})
|
|
```
|
|
|
|
For bash commands:
|
|
```typescript
|
|
// Add timeout to bash command
|
|
command: "timeout 60s long-running-command"
|
|
```
|
|
|
|
### Prevention
|
|
- Set reasonable timeouts
|
|
- Optimize tool implementations
|
|
- Use background jobs for long tasks
|
|
- Test tools independently
|
|
|
|
---
|
|
|
|
## Error #6: Session Not Found
|
|
|
|
### Error Message
|
|
```
|
|
"Invalid session ID"
|
|
"Session not found"
|
|
```
|
|
|
|
### Why It Happens
|
|
- Session ID is incorrect
|
|
- Session expired (old)
|
|
- Session from different CLI instance
|
|
|
|
### Solution
|
|
```typescript
|
|
// Ensure session ID captured correctly
|
|
let sessionId: string | undefined;
|
|
for await (const message of response) {
|
|
if (message.type === 'system' && message.subtype === 'init') {
|
|
sessionId = message.session_id; // Capture here
|
|
console.log("Session:", sessionId); // Verify
|
|
}
|
|
}
|
|
|
|
// Use correct session ID
|
|
query({
|
|
prompt: "...",
|
|
options: { resume: sessionId } // Must match exactly
|
|
});
|
|
```
|
|
|
|
### Prevention
|
|
- Always capture session_id from system init
|
|
- Store session IDs reliably
|
|
- Don't rely on sessions lasting indefinitely
|
|
- Handle session errors gracefully
|
|
|
|
---
|
|
|
|
## Error #7: MCP Server Connection Failed
|
|
|
|
### Error Message
|
|
```
|
|
"Server connection error"
|
|
"MCP server not responding"
|
|
"Failed to connect to MCP server"
|
|
```
|
|
|
|
### Why It Happens
|
|
- Server command/URL incorrect
|
|
- Server crashed or not running
|
|
- Network issues (HTTP/SSE servers)
|
|
- Missing dependencies
|
|
|
|
### Solution
|
|
|
|
For stdio servers:
|
|
```typescript
|
|
// Verify command works independently
|
|
// Test: npx @modelcontextprotocol/server-filesystem
|
|
options: {
|
|
mcpServers: {
|
|
"filesystem": {
|
|
command: "npx", // Verify npx is available
|
|
args: ["@modelcontextprotocol/server-filesystem"],
|
|
env: {
|
|
ALLOWED_PATHS: "/path" // Verify path exists
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
For HTTP servers:
|
|
```typescript
|
|
// Test URL separately
|
|
const testResponse = await fetch("https://api.example.com/mcp");
|
|
console.log(testResponse.status); // Should be 200
|
|
```
|
|
|
|
### Prevention
|
|
- Test MCP servers independently before integration
|
|
- Verify command/URL works
|
|
- Add error handling for server failures
|
|
- Use health checks
|
|
|
|
---
|
|
|
|
## Error #8: Subagent Definition Error
|
|
|
|
### Error Message
|
|
```
|
|
"Invalid AgentDefinition"
|
|
"Agent configuration error"
|
|
```
|
|
|
|
### Why It Happens
|
|
- Missing required fields (`description` or `prompt`)
|
|
- Invalid `model` value
|
|
- Invalid `tools` array
|
|
|
|
### Solution
|
|
```typescript
|
|
agents: {
|
|
"my-agent": {
|
|
description: "Clear description of when to use", // Required
|
|
prompt: "Detailed system prompt", // Required
|
|
tools: ["Read", "Write"], // Optional
|
|
model: "sonnet" // Optional
|
|
}
|
|
}
|
|
```
|
|
|
|
### Prevention
|
|
- Always include `description` and `prompt`
|
|
- Use TypeScript types
|
|
- Test agent definitions
|
|
- Follow examples in templates
|
|
|
|
---
|
|
|
|
## Error #9: Settings File Not Found
|
|
|
|
### Error Message
|
|
```
|
|
"Cannot read settings"
|
|
"Settings file not found"
|
|
```
|
|
|
|
### Why It Happens
|
|
- `settingSources` includes non-existent file
|
|
- File path incorrect
|
|
- File permissions deny read
|
|
|
|
### Solution
|
|
```typescript
|
|
// Check file exists before loading
|
|
import fs from 'fs';
|
|
|
|
const projectSettingsPath = '.claude/settings.json';
|
|
const settingSources = [];
|
|
|
|
if (fs.existsSync(projectSettingsPath)) {
|
|
settingSources.push('project');
|
|
}
|
|
|
|
options: {
|
|
settingSources // Only existing files
|
|
}
|
|
```
|
|
|
|
### Prevention
|
|
- Check file exists before including in sources
|
|
- Use empty array for isolated execution
|
|
- Handle missing files gracefully
|
|
|
|
---
|
|
|
|
## Error #10: Tool Name Collision
|
|
|
|
### Error Message
|
|
```
|
|
"Duplicate tool name"
|
|
"Tool already defined"
|
|
```
|
|
|
|
### Why It Happens
|
|
- Two MCP servers define same tool name
|
|
- Tool name conflicts with built-in tool
|
|
|
|
### Solution
|
|
```typescript
|
|
// Use unique tool names
|
|
const server1 = createSdkMcpServer({
|
|
name: "service-a",
|
|
tools: [
|
|
tool("service_a_process", ...) // Prefix with server name
|
|
]
|
|
});
|
|
|
|
const server2 = createSdkMcpServer({
|
|
name: "service-b",
|
|
tools: [
|
|
tool("service_b_process", ...) // Different name
|
|
]
|
|
});
|
|
```
|
|
|
|
### Prevention
|
|
- Use unique tool names
|
|
- Prefix tools with server name
|
|
- Test integration before deployment
|
|
|
|
---
|
|
|
|
## Error #11: Zod Schema Validation Error
|
|
|
|
### Error Message
|
|
```
|
|
"Invalid tool input"
|
|
"Schema validation failed"
|
|
```
|
|
|
|
### Why It Happens
|
|
- Agent provided data that doesn't match Zod schema
|
|
- Schema too restrictive
|
|
- Missing `.describe()` on fields
|
|
|
|
### Solution
|
|
```typescript
|
|
// Add descriptive schemas
|
|
{
|
|
email: z.string().email().describe("User email address"),
|
|
age: z.number().int().min(0).max(120).describe("Age in years"),
|
|
role: z.enum(["admin", "user"]).describe("User role")
|
|
}
|
|
|
|
// Make fields optional if appropriate
|
|
{
|
|
email: z.string().email(),
|
|
phoneOptional: z.string().optional() // Not required
|
|
}
|
|
```
|
|
|
|
### Prevention
|
|
- Use `.describe()` on all fields
|
|
- Add validation constraints
|
|
- Test with various inputs
|
|
- Make optional fields explicit
|
|
|
|
---
|
|
|
|
## Error #12: Filesystem Permission Denied
|
|
|
|
### Error Message
|
|
```
|
|
"Access denied"
|
|
"Cannot access path"
|
|
"EACCES: permission denied"
|
|
```
|
|
|
|
### Why It Happens
|
|
- Path outside `workingDirectory`
|
|
- No read/write permissions
|
|
- Protected system directory
|
|
|
|
### Solution
|
|
```typescript
|
|
// Set correct working directory
|
|
options: {
|
|
workingDirectory: "/path/to/accessible/dir"
|
|
}
|
|
|
|
// Or fix permissions
|
|
// chmod +r file.txt (add read)
|
|
// chmod +w file.txt (add write)
|
|
```
|
|
|
|
### Prevention
|
|
- Set appropriate `workingDirectory`
|
|
- Verify file permissions
|
|
- Don't access system directories
|
|
- Use dedicated project directories
|
|
|
|
---
|
|
|
|
## General Error Handling Pattern
|
|
|
|
```typescript
|
|
try {
|
|
const response = query({ prompt: "...", options: { ... } });
|
|
|
|
for await (const message of response) {
|
|
if (message.type === 'error') {
|
|
console.error('Agent error:', message.error);
|
|
// Handle non-fatal errors
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Fatal error:', error);
|
|
|
|
// Handle specific errors
|
|
switch (error.code) {
|
|
case 'CLI_NOT_FOUND':
|
|
console.error('Install: npm install -g @anthropic-ai/claude-code');
|
|
break;
|
|
case 'AUTHENTICATION_FAILED':
|
|
console.error('Check ANTHROPIC_API_KEY');
|
|
break;
|
|
case 'RATE_LIMIT_EXCEEDED':
|
|
console.error('Rate limited. Retry with backoff.');
|
|
break;
|
|
case 'CONTEXT_LENGTH_EXCEEDED':
|
|
console.error('Reduce context or fork session');
|
|
break;
|
|
default:
|
|
console.error('Unexpected error:', error);
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
**For more details**: See SKILL.md
|
|
**Template**: templates/error-handling.ts
|