Skip to main content
This page covers the most common problems developers run into when setting up and using @vibesjs/sdk.

Setup issues

Wrong registry: npm:@vibesjs/sdk

If you import from npm:@vibesjs/sdk instead of jsr:@vibesjs/sdk, the import resolves silently but produces no useful exports — the npm name is a placeholder stub. Fix: Always use the JSR registry.
// deno.json
{
  "imports": {
    "@vibesjs/sdk": "jsr:@vibesjs/sdk@^1.0"   // correct
  //  "@vibesjs/sdk": "npm:@vibesjs/sdk"        // wrong — stub package
  }
}
For Node.js, install via the JSR CLI:
npx jsr add @vibesjs/sdk

Zod version mismatch (v3 vs v4)

Vibes requires Zod v4. Installing zod without a version pin may give you Zod v3, which has a different API. Symptoms include TypeScript errors on z.object, z.string, and similar. Fix:
# Node.js
npm install zod@^4

# Deno — pin in your import map
"zod": "npm:zod@^4"

Missing API key

Every provider requires an API key set as an environment variable. If the key is absent, the provider throws a 401 or similar authentication error at runtime. Fix: Export the key before running your script:
export ANTHROPIC_API_KEY="sk-ant-..."   # Anthropic
export OPENAI_API_KEY="sk-..."          # OpenAI
export GOOGLE_GENERATIVE_AI_API_KEY="..." # Google
Never commit API keys to source control. Add .env to your .gitignore and use your deployment platform’s secret management in production.

Deno cache corruption

If Deno reports a missing export for a package that exists, a corrupted cache entry may be to blame. This can happen after a failed or partial download. Detect: The import resolves but z (or another export) is undefined at runtime. Fix: Clear the affected entry and re-run:
# Remove the specific package from Deno's npm cache
rm -rf ~/Library/Caches/deno/npm/registry.npmjs.org/<package>/<version>

# Deno re-fetches automatically on next run
deno run --allow-env --allow-net your_script.ts
Replace <package> and <version> with the affected package (e.g. zod/4.0.0).

Provider errors

APICallError / connection refused

This usually means the provider’s API is unreachable or the model name is incorrect. Check:
  1. Your API key is set and valid.
  2. The model string matches the provider’s naming (e.g. "claude-sonnet-4-6" for Anthropic, "gpt-4o" for OpenAI).
  3. You have network access from where the script runs.

Model not found

Passing an unrecognised model ID to a provider function causes the provider to reject the request.
// Wrong - invented model name
anthropic("claude-ultra-9000")

// Correct - check provider docs for valid model IDs
anthropic("claude-sonnet-4-6")

Understanding error classes

@vibesjs/sdk throws typed errors that you can catch and handle specifically. Import them from jsr:@vibesjs/sdk:
Error classWhen it is thrown
MaxTurnsErrorThe agent exceeded maxTurns without producing a final result
MaxRetriesErrorResult validation failed after all configured retries
UsageLimitErrorA token or request limit set via usageLimits was exceeded
ApprovalRequiredErrorA tool with requiresApproval: true was called and needs human sign-off
ModelRequestsDisabledErrorA real model call was made while setAllowModelRequests(false) is active in tests

Catching a specific error

import { Agent, MaxTurnsError, UsageLimitError } from "jsr:@vibesjs/sdk";

try {
  const result = await agent.run("Do a complex task");
  console.log(result.output);
} catch (err) {
  if (err instanceof MaxTurnsError) {
    console.error("Agent ran too long — increase maxTurns or simplify the task.");
  } else if (err instanceof UsageLimitError) {
    console.error(`Limit exceeded: ${err.limitKind} reached ${err.current} (limit: ${err.limit})`);
  } else {
    throw err; // re-throw unexpected errors
  }
}

UsageLimitError fields

When you catch a UsageLimitError, it carries three properties:
PropertyTypeDescription
limitKind"requests" | "inputTokens" | "outputTokens" | "totalTokens"Which limit was exceeded
currentnumberUsage at the point of failure
limitnumberThe configured cap

Debugging failed tool calls

When a tool call fails, the SDK feeds the error back to the model so it can retry or adjust. If failures persist, add logging inside your execute function:
import { tool } from "jsr:@vibesjs/sdk";
import { z } from "zod";

const myTool = tool({
  name: "my_tool",
  description: "Does something",
  parameters: z.object({ input: z.string() }),
  execute: async (_ctx, { input }) => {
    console.log("[my_tool] called with:", input);
    try {
      const result = await doSomething(input);
      console.log("[my_tool] result:", result);
      return result;
    } catch (err) {
      console.error("[my_tool] error:", err);
      throw err; // let the SDK handle the retry
    }
  },
});
Set maxRetries on a tool to control how many times the SDK retries a failing execution before propagating the error to the model as a permanent failure.

Common Zod schema mistakes

Using .optional() on required parameters

The model will not pass optional fields reliably. Prefer explicit defaults or separate tools.
// Avoid: model may omit the field unpredictably
parameters: z.object({ city: z.string().optional() })

// Better: always require it, let the model ask for clarification
parameters: z.object({ city: z.string().describe("City name, required") })

Forgetting .describe() on fields

Without descriptions, the model has no guidance on what each field means. Always add .describe() to every parameter.
// Missing descriptions
parameters: z.object({ q: z.string(), n: z.number() })

// With descriptions — much better model behaviour
parameters: z.object({
  q: z.string().describe("Search query"),
  n: z.number().describe("Maximum number of results to return"),
})

Overly deep or recursive schemas

Deeply nested or self-referential Zod schemas can cause providers to reject the generated JSON Schema. Keep tool parameters flat where possible.

Next steps