Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.zavu.dev/llms.txt

Use this file to discover all available pages before exploring further.

Debugging Functions

When your function isn’t behaving, the issue is usually in one of these layers:
┌─────────────────────────────────────────────────┐
│ 1. Inbound message               (does it arrive?)
├─────────────────────────────────────────────────┤
│ 2. Agent dispatch                (does the agent run?)
├─────────────────────────────────────────────────┤
│ 3. LLM call                      (does the LLM respond?)
├─────────────────────────────────────────────────┤
│ 4. Tool invocation               (does the tool get called?)
├─────────────────────────────────────────────────┤
│ 5. Tool handler                  (does YOUR code work?)
└─────────────────────────────────────────────────┘
Walk the layers top-to-bottom. The first one that fails is the one to fix.

1. Did the inbound message arrive?

Open the dashboard → Senders → your sender → Conversations.
  • No message visible: the inbound never reached Zavu. Check your sender’s webhook (WhatsApp, Telegram) is wired up. The dashboard shows webhook config and recent delivery attempts.
  • Message visible, no reply: inbound is fine, problem is downstream. Go to step 2.

2. Did the agent run?

zavu agents executions list --sender <senderId>
This is the most useful debug command. Three possible states:

a) “No executions.”

The inbound arrived but the agent dispatcher didn’t even try to invoke the agent. Causes:
Likely causeCheck
Wrong SENDER_ID secret on the functionzavu fn secrets list — last 4 chars of the value must match the senderId you’re testing
Agent disabledzavu agents get --sender <senderId>enabled must be true
Channel filtered outtriggerOnChannels doesn’t include the inbound’s channel. Use ["*"] or include the specific one (e.g. "telegram")
Message type filtered outtriggerOnMessageTypes excludes the type (e.g. you sent an image and only "text" is allowed)
Empty message textThe dispatcher skips messages with no text. Inbound types like reactions or system events don’t trigger agents

b) status: error

The agent ran but something blew up. Fetch the full detail:
zavu agents executions get <executionId> --sender <senderId>
You’ll see errorMessage and errorCode. Common error categories:
errorCodeMeaningFix
balance_insufficientProvider zavu ran out of AI gateway balanceTop up balance in dashboard, or switch to BYOK by setting provider + apiKey in defineAgent
rate_limitedHit the LLM provider’s rate limitLower concurrency or wait
provider_errorLLM provider rejected the callCheck the message text — sometimes prompts trigger safety filters. Also verify your model ID is valid for the provider
tool_not_foundAgent tried to call a tool that doesn’t existTool name in defineTool doesn’t match what the LLM is calling. Or the deploy didn’t reconcile — run zavu deploy again
tool_errorA tool handler threwCheck the tool’s source. The errorMessage includes the handler’s exception text

c) status: success but no message sent back

The agent succeeded but didn’t reply. Look at responseText in the execution detail — if it’s empty, the LLM returned nothing useful. Adjust your systemPrompt to encourage replies, or check that the model isn’t returning just tool calls without a final response.

3. Is the LLM working?

If executions are failing with provider_error:
zavu agents executions get <executionId> --sender <senderId> --json
Look at the full errorMessage. Typical issues:
  • Bad model ID: e.g. openai/gpt-4o-mini works on provider: "zavu" (our gateway uses prefixed IDs), but the raw gpt-4o-mini works on provider: "openai" directly.
  • Expired API key (when using provider: "openai" etc.): rotate the key and update the agent’s apiKey.
  • Tool schema malformed: rare, but if your defineTool parameters JSON Schema has a typo, the LLM’s tool-calling step can fail. Validate the schema renders to valid JSON.

4. Did the tool get called?

Once the agent runs successfully but you suspect the tool wasn’t invoked, check the function logs:
zavu fn logs --tail
Then send a message that should trigger the tool. You should see:
[ctx.log] <your console.log output>
If you see nothing in the function logs but agents executions shows success, the LLM chose not to call the tool. Tighten the tool’s description so the LLM understands when to call it.

5. Is the tool handler buggy?

Once you confirm the tool is being called, isolate it locally:
zavu fn invoke --tool view_menu --args '{"filter":"vegan"}'
This runs the handler with synthetic args and prints the result. Iterate locally without redeploying. For deeper debugging, add ctx.log calls inside the handler:
defineTool({
  name: "lookup_order",
  // ...
  handler: async (args, ctx) => {
    ctx.log("lookup_order called with", args)
    const order = await fetchOrder(args.orderId)
    ctx.log("found order", { id: order?.id, status: order?.status })
    return order
  },
})
Then zavu deploy and zavu fn logs --tail while triggering the tool from a real conversation. The [ctx.log] lines appear in the live tail.

Reconcile didn’t pick up my new agent / tool

When you run zavu deploy, the platform reads your defineAgent / defineTool declarations from a manifest probe Lambda invocation, then reconciles the live agent + tools to match. If you see:
! manifest probe: manifest probe threw: defineAgent: senderId is required.
…the issue is your code threw at module load time. Common causes:
  • Missing required secret: e.g. process.env.SENDER_ID! evaluates to undefined because you didn’t set the secret yet. Fix: zavu fn secrets set SENDER_ID <value> then zavu deploy.
  • Syntax error in your index.ts: the bundler caught it earlier but some edge cases get through. Run tsc --noEmit locally before deploying.

Local invocation cheat sheet

GoalCommand
Test a single tool handlerzavu fn invoke --tool <name> --args '{...}'
Test an event handler (defineFunction)zavu fn invoke --event message.inbound --data '{...}'
Tail live production logszavu fn logs --tail
Query recent agent runszavu agents executions list --sender <senderId>
Full detail of one runzavu agents executions get <executionId> --sender <senderId>
Inspect the agent configzavu agents get --sender <senderId>
Inspect tools attachedzavu agents tools list --sender <senderId>
See what secrets are setzavu fn secrets list

When all else fails

  1. Add ctx.log("got here", { someState }) aggressively in your handler.
  2. zavu deploy and zavu fn logs --tail simultaneously.
  3. Trigger the flow from a real conversation.
  4. Read the logs top-to-bottom — the first absence of expected output is the layer that’s failing.
  5. Open a ticket with the function ID, the executionId that failed, and the timestamp. Support can pull internal traces faster than guessing.