Skip to Content
DocumentationTroubleshooting

Troubleshooting

Common issues and solutions when working with GuideKit.

Setup Issues

Missing API Key

Symptom: GuideKitError: LLM_API_KEY_MISSING on initialization.

Fix (production): Use proxy mode with server-side keys. Run npx guidekit init to scaffold lib/guidekit-routes.ts and /api/guidekit/* routes, then set GUIDEKIT_SECRET and LLM_API_KEY in .env.local. See Getting Started.

Fix (dev only): You can pass a client key for quick prototyping — never ship this to production:

<GuideKitProvider llm={{ provider: 'gemini', apiKey: process.env.NEXT_PUBLIC_GEMINI_KEY! }} >

For production, use the Server SDK to keep API keys server-side.

Wrong Provider Configuration

Symptom: GuideKitError: LLM_PROVIDER_INVALID or unexpected model responses.

Fix: Check that the type field matches your API key provider:

// Gemini llm={{ provider: 'gemini', apiKey: '...' }} // OpenAI llm={{ provider: 'openai', apiKey: '...' }} // Anthropic llm={{ provider: 'anthropic', apiKey: '...' }}

SDK Not Initializing

Symptom: isReady stays false, no errors visible.

Fix:

  1. Ensure <GuideKitProvider> wraps your app at the top level.
  2. Check browser console for errors — enable debug mode for detailed logs:
<GuideKitProvider options={{ debug: true }} proxy={{ llm: '/api/guidekit/llm', health: '/api/guidekit/health' }} tokenEndpoint="/api/guidekit/token" >
  1. Verify you are not rendering on the server without SSR guards.

Voice Mode Issues

Microphone Permission Denied

Symptom: GuideKitError: PERMISSION_DENIED when starting voice.

Fix:

  1. Ensure your site is served over HTTPS (microphone access requires a secure context).
  2. Check browser settings to confirm the microphone permission is not blocked for your domain.
  3. Call startListening() in response to a user gesture (click, tap) — browsers block mic access without user interaction.

Browser Compatibility

Voice features require:

  • Chrome 89+ / Edge 89+ — full support (Web Speech API + AudioContext)
  • Safari 15.4+ — supported with webkitAudioContext fallback
  • Firefox 100+ — Web Speech API support varies; Deepgram STT recommended

If voice is unavailable, use the checkCapabilities() method to detect support:

const caps = await core.checkCapabilities(); if (caps.mic.status === 'unavailable') { // Hide voice UI }

Echo Detection / Feedback Loop

Symptom: The assistant hears its own TTS output and responds to it.

Fix: GuideKit includes built-in echo detection (60% word overlap within a 3-second window). If you experience echo issues:

  1. Use headphones during testing.
  2. Ensure TTS playback volume is not excessively high.
  3. The half-duplex state machine prevents listening while speaking — verify your state transitions are correct.

Bundle Size Issues

Bundle Larger Than Expected

Symptom: Production bundle exceeds expected size limits.

Fix:

  1. Use subpath imports to enable tree-shaking:
// Preferred — only imports what you need import { GuideKitProvider } from '@guidekit/react'; import { createGuideKit } from '@guidekit/core'; // Avoid — may pull in unnecessary code import * as GuideKit from '@guidekit/core';
  1. If you do not use voice features, avoid importing from @guidekit/vad.

  2. Verify tree-shaking is working with your bundler. All GuideKit packages set sideEffects: false.

  3. Run the size check to see current bundle sizes:

pnpm size:check

Expected gzip sizes: core 65KB, react 8KB, server 2KB, vanilla 92KB, cli 5KB.

Rendering Subpath Not Tree-Shaken

If you only use the core SDK without visual guidance, import from the base path:

import { createGuideKit } from '@guidekit/core';

Visual/rendering exports live under @guidekit/core/rendering to keep the vanilla bundle smaller.

Production / Proxy Failures

Session expired or server restarted (401)

Symptom: LLM proxy returns 401 with “Session expired or server restarted — request a new token”.

Cause: Provider keys live in the server SessionStore, keyed by sessionId. After a deploy/restart (in-memory store) or TTL expiry, the JWT may still decode but keys are gone.

Fix:

  1. Ensure the client refreshes tokens (GuideKit refreshes at ~80% TTL automatically).
  2. For multi-instance/serverless, use RedisSessionStore.
  3. See Session recovery below.

Rate limit exceeded (429)

Symptom: Proxy returns 429 with Retry-After.

Fix: Back off and retry after the header value. Tune rateLimit.maxRequests on createGuideKitHandler — see Server SDK rate limiting.

Origin not allowed (403)

Symptom: Proxy returns 403 with “Origin not allowed”.

Fix: Ensure allowedOrigins on createSessionToken includes your app’s origin (scheme + host + port). Browser fetch from the app must send a matching Origin header.

Permission denied (403)

Symptom: STT/TTS/LLM/site-search proxy returns 403 with Permission “llm” not granted (or stt / tts / site:read).

Fix: Mint tokens with the required permissions array, e.g. ['stt', 'tts', 'llm', 'site:read'] (default).

Recoverable vs non-recoverable errors

Every GuideKitError includes recoverable:

recoverableMeaningExamples
trueSafe to retry or continueSEND_IN_FLIGHT, INPUT_TOO_LONG, rate limits, network blips
falseFix configuration or authMissing LLM config, invalid provider, fatal init errors

Client pattern:

core.bus.on('error', (err) => { if (err.recoverable) { // show toast, allow retry return; } // log to monitoring, show support message });

Use Observability (DevTools Telemetry tab or core.getTelemetrySpans()) to see which pipeline stage failed before the error surfaced.

Session recovery (client-side)

When the LLM proxy returns 401, the SDK should fetch a new token and retry. Contract coverage: e2e/contract/session-recovery.spec.ts.

If recovery loops:

  1. Confirm /api/guidekit/token returns 200 and LLM_API_KEY is set server-side.
  2. Confirm all app instances share the same SessionStore (Redis in production).
  3. Enable options={{ debug: true }} and watch auth:token-refreshed events.

Error Codes

GuideKit uses structured error codes for all failures. Each GuideKitError includes:

  • code — a machine-readable error code
  • message — a human-readable description
  • recoverable — whether the error can be retried
  • suggestion — a recommended fix

See the full Error Codes Reference for a complete list.

Debug Mode

Enable debug mode for verbose console output:

<GuideKitProvider options={{ debug: true }} proxy={{ llm: '/api/guidekit/llm', health: '/api/guidekit/health' }} tokenEndpoint="/api/guidekit/token" >

This logs:

  • EventBus events and handler execution
  • LLM request/response cycles and tool calls
  • DOM scanning and section detection
  • Voice state machine transitions
  • Resource manager lifecycle events

For programmatic access, subscribe to the error event on the EventBus:

const core = createGuideKit({ debug: true, provider: { ... } }); core.bus.on('error', (err) => { // Send to your error tracking service myErrorTracker.capture(err); });
Last updated on