Skip to main content

Troubleshooting Guide

This guide covers common issues and solutions when developing with Spritz.

Authentication Issues

"Session not found" or "Unauthorized" Errors

Symptoms:

  • API returns 401 Unauthorized
  • User appears logged out unexpectedly
  • Actions fail with session errors

Solutions:

  1. Check credentials mode in fetch requests:
// ❌ Wrong - cookies won't be sent
fetch('/api/agents');

// ✅ Correct - include credentials
fetch('/api/agents', { credentials: 'include' });
  1. Verify cookie domain settings:
// In your auth verification, ensure cookies are set correctly
cookies().set('session', token, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 60 * 60 * 24 * 7, // 7 days
path: '/',
});
  1. Check session expiration:
// Sessions expire after 7 days by default
// Check JWT expiration
import { jwtVerify } from 'jose';

const { payload } = await jwtVerify(token, secretKey);
if (payload.exp && payload.exp < Date.now() / 1000) {
console.log('Session expired');
}

Passkey Authentication Fails

Symptoms:

  • "Passkey not found" error
  • WebAuthn assertion fails
  • Cross-device authentication issues

Solutions:

  1. Verify origin matches:
// Origin must match exactly
const expectedOrigin = process.env.NEXT_PUBLIC_APP_URL;
const { origin } = new URL(clientData.origin);

if (origin !== expectedOrigin) {
throw new Error(`Origin mismatch: ${origin} !== ${expectedOrigin}`);
}
  1. Check RP ID configuration:
// RP ID should be the domain without protocol
const rpId = 'spritz.chat'; // Not 'https://spritz.chat'
  1. Handle cross-device passkeys:
// Some passkeys are device-bound, others are synced
// Check the authenticator flags
const isDeviceBound = !(flags & 0x01); // UP flag check

SIWE Signature Verification Fails

Symptoms:

  • "Invalid signature" error
  • Nonce mismatch
  • Message format errors

Solutions:

  1. Verify message format:
import { SiweMessage } from 'siwe';

// Ensure message is prepared correctly
const message = new SiweMessage({
domain: window.location.host,
address: address,
statement: 'Sign in to Spritz',
uri: window.location.origin,
version: '1',
chainId: 8453,
nonce: nonce,
});

// Use prepareMessage() not toString()
const messageToSign = message.prepareMessage();
  1. Check nonce validity:
// Nonce is returned with the SIWE message from the server
// and must be used within 5 minutes
const { message, nonce } = await fetch(`/api/auth/verify?address=${address}`).then(r => r.json());

// The nonce is already embedded in the message
// Just sign and submit within the validity window

Database Issues

"Relation does not exist" Error

Symptoms:

  • ERROR: relation "table_name" does not exist
  • Queries fail after deployment
  • Missing tables or columns

Solutions:

  1. Run migrations in order:
# Migrations must be run alphabetically
ls -1 migrations/*.sql | sort | while read f; do
psql -d spritz -f "$f"
done
  1. Check for missing dependencies:
-- Some tables depend on others
-- Run core tables first:
-- 1. agents.sql
-- 2. embeddings.sql
-- Then dependent tables:
-- 3. agents_x402.sql (requires agents)
  1. Verify schema:
-- Check if table exists
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = 'your_table'
);

Vector Search Not Working

Symptoms:

  • RAG returns no results
  • Similarity search fails
  • pgvector extension errors

Solutions:

  1. Enable pgvector extension:
-- Must be enabled before creating vector columns
CREATE EXTENSION IF NOT EXISTS vector;
  1. Check embedding dimensions:
-- Gemini embeddings are 768 dimensions
ALTER TABLE embeddings
ALTER COLUMN embedding TYPE vector(768);
  1. Create index for performance:
-- Use IVFFlat for larger datasets
CREATE INDEX ON embeddings
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);

RLS Policy Blocks Access

Symptoms:

  • Queries return empty results
  • "Permission denied" errors
  • Data visible in admin but not API

Solutions:

  1. Check RLS is enabled:
-- Verify RLS status
SELECT tablename, rowsecurity
FROM pg_tables
WHERE schemaname = 'public';
  1. Debug policy evaluation:
-- Temporarily check what user sees
SET ROLE authenticated;
SET request.jwt.claim.sub = 'user_address';
SELECT * FROM agents; -- See what RLS allows
RESET ROLE;
  1. Common policy pattern:
-- Ensure policy covers your use case
CREATE POLICY "Users can view own agents"
ON agents FOR SELECT
USING (owner_address = auth.jwt() ->> 'sub');

Messaging Issues

Logos Messaging (Waku) - Messages Not Delivering

Terminology

Spritz uses Logos Messaging (built on the Waku protocol) for decentralized peer-to-peer messaging. In code, you may see references to @waku/sdk as Logos Messaging uses Waku under the hood.

Symptoms:

  • Messages sent but not received
  • Intermittent message loss
  • High latency

Solutions:

  1. Check content topic format:
// Content topics must follow the format
const contentTopic = `/spritz/1/dm-${sortedAddresses}/proto`;

// Addresses must be sorted consistently
const sortedAddresses = [addr1, addr2].sort().join('-');
  1. Verify peer connections:
import { waitForRemotePeer, Protocols } from '@waku/sdk';

// Wait for peers before sending
await waitForRemotePeer(node, [
Protocols.Filter,
Protocols.LightPush,
]);

console.log('Connected peers:', node.libp2p.getPeers().length);
  1. Handle message encoding:
// Messages must be properly encoded
const encoder = createEncoder({
contentTopic,
pubsubTopic: '/waku/2/default-waku/proto',
});

const payload = proto.Message.encode({
content: message,
timestamp: Date.now(),
sender: address,
}).finish();

Realtime Subscriptions Not Working

Symptoms:

  • Supabase realtime events not firing
  • Channel joins fail
  • Updates not reflected in UI

Solutions:

  1. Enable realtime for table:
-- In Supabase dashboard or via SQL
ALTER PUBLICATION supabase_realtime ADD TABLE your_table;
  1. Check channel subscription:
const channel = supabase
.channel('room1')
.on(
'postgres_changes',
{
event: '*',
schema: 'public',
table: 'messages',
filter: `channel_id=eq.${channelId}`,
},
(payload) => {
console.log('Change received:', payload);
}
)
.subscribe((status) => {
if (status === 'SUBSCRIBED') {
console.log('Subscribed!');
}
});
  1. Verify RLS allows subscription:
-- RLS policies also apply to realtime
-- Ensure SELECT policy exists
CREATE POLICY "Allow reading messages"
ON messages FOR SELECT
USING (true); -- Or your specific condition

Video Call Issues

Huddle01 Room Creation Fails

Symptoms:

  • "Invalid API key" error
  • Room creation returns null
  • Token generation fails

Solutions:

  1. Check environment variables:
# Required variables
HUDDLE01_API_KEY=your_api_key
HUDDLE01_PROJECT_ID=your_project_id
  1. Verify API key scope:
// API key must have room creation permissions
const response = await fetch('https://api.huddle01.com/api/v1/create-room', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.HUDDLE01_API_KEY,
},
body: JSON.stringify({
title: roomTitle,
roomLocked: false,
}),
});

if (!response.ok) {
const error = await response.json();
console.error('Huddle01 error:', error);
}
  1. Handle rate limits:
// Huddle01 has rate limits
// Implement exponential backoff
const delay = Math.min(1000 * Math.pow(2, retryCount), 10000);
await new Promise(r => setTimeout(r, delay));

Screen Sharing Not Working

Symptoms:

  • Screen share button disabled
  • "NotAllowedError" in console
  • Black screen on share

Solutions:

  1. Check HTTPS:
// Screen sharing requires secure context
if (!window.isSecureContext) {
console.error('Screen sharing requires HTTPS');
}
  1. Handle permissions:
try {
const stream = await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: true,
});
} catch (err) {
if (err.name === 'NotAllowedError') {
// User denied permission
} else if (err.name === 'NotFoundError') {
// No screen sharing available
}
}

Deployment Issues

Build Fails with Type Errors

Symptoms:

  • tsc reports errors
  • Import resolution fails
  • Module not found

Solutions:

  1. Check TypeScript version:
{
"devDependencies": {
"typescript": "^5.0.0"
}
}
  1. Verify path aliases:
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./*"]
}
}
}
  1. Clear cache and rebuild:
rm -rf .next node_modules/.cache
npm run build

Environment Variables Not Loading

Symptoms:

  • undefined for env vars
  • Different behavior in dev vs prod
  • Client-side vars not available

Solutions:

  1. Use correct prefix:
# Server-side only
DATABASE_URL=postgres://...

# Available in browser (Next.js)
NEXT_PUBLIC_APP_URL=https://app.spritz.chat
  1. Check .env file location:
project/
├── .env.local # Local overrides (gitignored)
├── .env.development # Dev defaults
├── .env.production # Prod defaults
└── .env # Shared defaults
  1. Verify in runtime:
// Debug env loading
console.log('Env check:', {
hasDbUrl: !!process.env.DATABASE_URL,
appUrl: process.env.NEXT_PUBLIC_APP_URL,
});

Performance Issues

Slow API Responses

Symptoms:

  • Requests take > 1 second
  • Timeouts on complex queries
  • High database CPU

Solutions:

  1. Add database indexes:
-- Index frequently queried columns
CREATE INDEX idx_agents_owner ON agents(owner_address);
CREATE INDEX idx_messages_channel ON channel_messages(channel_id);
CREATE INDEX idx_messages_created ON channel_messages(created_at DESC);
  1. Use pagination:
// Don't fetch all records
const { data } = await supabase
.from('messages')
.select('*')
.eq('channel_id', channelId)
.order('created_at', { ascending: false })
.range(0, 49); // Fetch 50 at a time
  1. Enable connection pooling:
// Use connection string with pooler
const connectionString = process.env.DATABASE_URL; // Should include ?pgbouncer=true

Memory Leaks in Development

Symptoms:

  • Node process grows continuously
  • Browser tab becomes slow
  • "JavaScript heap out of memory"

Solutions:

  1. Clean up subscriptions:
useEffect(() => {
const channel = supabase.channel('updates');

return () => {
supabase.removeChannel(channel);
};
}, []);
  1. Unsubscribe from Waku:
useEffect(() => {
const unsubscribe = node.filter.subscribe(/* ... */);

return () => {
unsubscribe();
};
}, []);

Common Error Code Reference

For a complete list of API error codes and their meanings, see the Error Codes Reference.

HTTP StatusCommon CauseQuick Fix
401Session expired or missing credentialsEnsure credentials: 'include' in fetch
402x402 payment requiredProvide valid X-Payment header
403Access denied / RLS policyCheck permissions and ownership
404Resource not foundVerify ID exists and is accessible
429Rate limit exceededImplement exponential backoff
500Server errorCheck logs and retry

Getting Help

If your issue isn't covered here:

  1. Check the FAQ for common questions
  2. Review Error Codes for API errors
  3. Search existing issues on GitHub
  4. Join the community channels for support

When reporting issues, include:

  • Error message and stack trace
  • Steps to reproduce
  • Environment (OS, Node version, browser)
  • Relevant code snippets