> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aisky.co.za/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting

> Most common HTTP Tools failures and how to debug them from the dashboard.

The Invocations panel in the tool manager is your primary debugging surface. Every call (live + test) lands there within 1-2 seconds with full request, response, latency, signature, and error code if any.

## "My tool isn't firing during calls"

The AI never chose to call it. Checks in order:

<Steps>
  <Step title="Is the tool active?">
    In the manager, the row should show a green dot and `Active`. If it says `Disabled`, hit Enable.
  </Step>

  <Step title="Is the agent-level toggle on?">
    In Agent Studio → Tools, the Custom HTTP Tools card should show `Active` (not `Configured`). If it says `Configured`, the master switch is off, toggle it.
  </Step>

  <Step title="Is the description aligned with what the caller said?">
    The AI uses the `description` to decide when to call. If your description says "use this for billing routing" and the caller asked about returns, the AI won't call it.

    Fix: make the description broader, or test with a more on-topic prompt.
  </Step>

  <Step title="Place a test call and watch the panel">
    Even on a misfire, the panel won't show anything (because no call happened). That's expected.
  </Step>
</Steps>

## "I see HTTP\_TOOL\_TIMEOUT in the log"

Your endpoint took longer than 10 seconds.

* Click the invocation row → see the full request URL.
* Try the URL yourself with `curl` (no signing needed for the timing test): `time curl -X POST https://your-url -d '{}'`.
* If your URL is slow, profile your code. Common culprits: cold-start serverless functions, slow DB queries, sync calls to external APIs.

## "I see HTTP\_TOOL\_CONNECTION\_FAILED"

DNS failed, TCP refused, or TLS handshake failed.

* Verify your endpoint resolves: `dig your-hostname.example.com`.
* Verify TLS works: `curl -v https://your-url 2>&1 | grep "SSL connection"`.
* Check certificate expiration: `openssl s_client -connect your-host:443 < /dev/null | openssl x509 -noout -dates`.
* Confirm public reachability from outside your network: `curl https://your-url` from a different network than your dev box.

## "I see HTTP\_TOOL\_URL\_BLOCKED"

SSRF guard fired at invocation time (DNS rebinding pattern).

Run `dig +short your-hostname.example.com` from your terminal. If any returned IP is in [the blocked ranges](/guides/http-tools/security-restrictions), that's why we rejected the call.

If your hostname genuinely resolves to a public IP but we still block, [open a ticket](mailto:hello@aisky.co.za) with the resolved IP, we'll investigate.

## "My signature verification keeps failing"

The most common signature-failure causes, in order:

<Steps>
  <Step title="You're hashing the parsed body, not the raw bytes.">
    Frameworks like Express, Flask, FastAPI parse JSON and discard the original bytes by default. You need to capture the **raw request body** before parsing.

    * Express: `express.json({ verify: (req, _, buf) => { req.rawBody = buf.toString() } })`
    * Flask: `request.get_data()` returns the raw bytes.
    * FastAPI: `await request.body()` returns the raw bytes.
    * Go: `io.ReadAll(r.Body)` once, then re-parse the bytes.
  </Step>

  <Step title="You're using the wrong signing secret.">
    Did you rotate the secret recently? The old one is dead the moment you click Rotate. Pull the latest from your environment and restart.
  </Step>

  <Step title="Your server clock is drifting.">
    We tolerate up to 60 seconds of future skew and 5 minutes of past skew. Anything beyond rejects. Sync via NTP.
  </Step>

  <Step title="You're using `==` instead of constant-time compare.">
    `==` works most of the time but is timing-attack-vulnerable AND occasionally fails on encoded vs raw forms. Always use `timingSafeEqual` / `hmac.compare_digest` / `hash_equals` / `hmac.Equal`.
  </Step>

  <Step title="Copy as curl in the dashboard and replay locally.">
    The Test panel's "Copy as curl" produces a complete curl command including the signed headers. Run it from your terminal against your endpoint. If that succeeds, your live setup is fine and the issue is in some intermediate proxy / WAF / CDN.
  </Step>
</Steps>

## "I see HTTP\_TOOL\_CUSTOMER\_ERROR"

Your endpoint returned 4xx or 5xx. Click the invocation row to see the response body preview.

| Status      | Likely cause                                                                                     |
| ----------- | ------------------------------------------------------------------------------------------------ |
| 401         | Your Bearer token check failed. Did the token in the tool config match what your server expects? |
| 403         | Your server is rejecting the request even with valid auth. App-level firewall?                   |
| 404         | Your URL path is wrong. The dashboard shows the exact URL we POSTed to.                          |
| 422         | Your server doesn't like the body shape. Maybe a required field is missing on your side.         |
| 500         | Unhandled exception. Check your error logs around the invocation timestamp.                      |
| 502/503/504 | Upstream is down. If you're behind a CDN, the CDN is upstream of you.                            |

## "My endpoint never receives the request"

If the dashboard shows a successful invocation but your server logs are empty:

* Are you sure you're looking at the right server? Check the URL in the invocation matches your real endpoint.
* Is there an in-front-of layer (Cloudflare, AWS WAF, Nginx) intercepting before your app sees it? Check its access logs.
* Are you filtering POST requests in your access logger? Some default configs log GET only.

If the dashboard shows `HTTP_TOOL_CONNECTION_FAILED` and your server logs are empty, you can't connect; see the earlier section.

## "I get HTTP\_TOOL\_RATE\_LIMITED unexpectedly"

You spent the bucket faster than refill. Common causes:

* **Tight inner loop in the AI's flow.** If your description leads the AI to call the tool every conversational turn, you'll burn through 30/min on one tool fast. Tighten the description so the AI calls it only when it has new info to look up.
* **Test fires bleeding into production.** They shouldn't, the test bucket is separate. If you see test-fire codes in your production invocations, [tell us](mailto:hello@aisky.co.za).
* **You genuinely need more.** Open a ticket; we lift caps per-tenant when justified.

## "I see HTTP\_TOOL\_INVALID\_ARGS"

The LLM passed args that don't match your `parameters_schema`. The AI usually corrects itself, but if you see this code repeating:

* Your schema is too strict (required fields the AI can't always provide).
* Your description doesn't tell the AI what shape to pass.

Fix: relax the schema (mark borderline fields optional) AND tighten the description ("Pass `query` as the caller's exact words.").

## "My response body shows up garbled in the dashboard but works for the AI"

The dashboard preview is **obfuscated**, provider names (vapi, twilio, asterisk, etc.) are replaced with `voice` to keep the UI provider-clean. The AI gets the verbatim body.

If you want the dashboard preview to read cleanly, don't put provider names in your response body. The AI doesn't need them.

## When to file a support ticket

If everything above doesn't pin down the issue, send us:

* Your tenant ID.
* The `invocation_id` from a failing row (UUID).
* A one-line "what I expected vs what happened."
* Your endpoint URL (we'll never share it).

[hello@aisky.co.za](mailto:hello@aisky.co.za). We aim for same-business-day on tool-related tickets.

<Card title="Back to: HTTP Tools overview" href="/guides/http-tools/overview">
  Top-level overview and links to every section.
</Card>
