# Debugging & Troubleshooting

## Common API Errors

### 400 "Invalid request body"
- `minimized_button_label` must be `{"enabled": true, "label": "..."}`, not a string
- `create_brandkit` requires `agent_id` in the JSON body (auto-handled by client)
- **Chat endpoints** (`/chat`, `/chat-test`, `/chat-preview`) return this when:
  - Agent has no published runtime config → publish first via `update_agent_instruction` + `publish_agent`
  - Backend service rejects the request format → this is a known backend issue, not a client bug

### 400 "No draft configuration found"
- `publish_agent` fails because no draft exists
- **Fix**: Call `update_agent_instruction(agent_id, instructions=...)` first — this creates the draft config
- `create_agent` with instructions does NOT create a draft runtime config

### 422 Validation Error
- `get_import_status` requires `url` query parameter matching the original import URL
- `create_knowledge_document` requires a real dataset UUID, NOT `new`

### 500 Internal Server Error
- **`import_knowledge_from_url`** — "Failed to import document: Expecting value: line 1 column 1 (char 0)":
  - **Root cause**: RAG service's `upload_webpage_to_knowledge_base()` in `dify_console_op.py` calls Dify's `/datasets/{id}/documents` API but does NOT check `response.status_code` before calling `response.json()`. When Dify returns a non-200 response (HTML error), JSON parsing fails.
  - **Underlying Dify failure**: Usually because the tenant has no `jinareader` API credentials configured. Dify needs valid provider credentials (jinareader/firecrawl/watercrawl) in its `api_key_auth` system.
- **`get_import_status`** — "Error fetching crawl status: HTTP 500":
  - **Root cause**: RAG's `check_crawl_status()` (line 778) hardcodes `provider=jinareader` in the Dify status URL. Dify's `WebsiteService` then calls `_get_credentials_and_config(tenant_id, "jinareader")` which raises "Invalid provider" if no credentials exist for that tenant+provider combo.
  - The actual Dify error is `{"code": "crawl_failed", "message": "Invalid provider", "status": 500}`.
- Google Sheets, Docs, and authenticated URLs always fail on import.

### 409 Conflict
- `create_brandkit` fails if a brandkit already exists — use `update_brandkit` instead
- Or use `fetch_brandkit(identifier=..., agent_id=...)` which handles create-or-update automatically

## Known Backend Issues (Not Client Bugs)

1. **`send_test_message` (chat-preview) returns 400** — was caused by using `message` field instead of `user_query`. The API service's `ExecuteRequest` requires `user_query` (binding:"required"). Fixed in client.
2. **`import_knowledge_from_url` returns 500** — RAG service doesn't check Dify response status before JSON parse; Dify fails because tenant lacks jinareader API credentials
3. **`get_import_status` returns 500** — RAG hardcodes `provider=jinareader` in Dify status URL; Dify rejects if tenant has no jinareader credentials configured
4. **`system_rules` via `update_agent` may not propagate** to published runtime config — embed guardrails in instructions instead
5. **`process_crawl_results_realtime` batch uploads fail** with "Expecting value" — same root cause as #2, Dify document upload returns non-JSON when credentials are missing

## Debugging Strategy

1. **Enable debug mode** (`--debug`) to see curl commands and API responses
2. **Check HTTP status codes**: 2xx = success, 4xx = client error (fix payload), 5xx = server/backend error
3. **For 400 errors**: Compare payload against OpenAPI spec in `astra-gateway/docs/openapi.yaml`
4. **For 500 errors**: Usually backend issues — try alternative approaches rather than retrying
5. **For chat errors**: Don't waste iterations retrying — verify agent is published (`get_runtime_config(status=active)`) first

## Efficiency Tips

- **Don't retry failing endpoints** — If `import_knowledge_from_url` fails once with 500, it will fail again. Switch to `import_knowledge_from_website` or manual documents.
- **Don't poll import status aggressively** — Status endpoint is unreliable. Start the crawl, do other work, check back later.
- **Use annotations early** — Don't wait for KB to be ready. Create annotations for guardrail responses immediately while import runs in background.
- **Batch annotation creation** — Create multiple annotations in sequence for different guardrail categories (fees, competitors, availability, redirects, facts).

## Performance Tips

- `list_agents` returns lightweight summaries (no instructions) — use `get_agent` for full details
- Truncate long content before sending to LLM (auto-handled at 8000 chars)
- Prompt caching is enabled automatically for Claude models — static content (system prompt + tools) cached for 5 minutes, ~90% savings on repeat calls
- Full agent creation workflow costs ~$2.50-3.50 with Claude Sonnet over ~25 iterations
