bknd-troubleshoot
Troubleshoot Common Errors
Quick-reference guide for resolving Bknd errors by error code, symptom, or common mistake pattern.
Prerequisites
- Bknd project running (or attempting to run)
- Error message or symptom to diagnose
Error Code Quick Reference
400 Bad Request
Cause: Invalid request body or parameters
Quick fixes:
# Check JSON validity
echo '{"title":"Test"}' | jq .
# Verify Content-Type header
curl -X POST http://localhost:3000/api/data/posts \
-H "Content-Type: application/json" \
-d '{"title":"Test"}'
Common causes:
- Missing
Content-Type: application/jsonheader - Malformed JSON body
- Missing required field
- Invalid field type (string instead of number)
- Invalid enum value
401 Unauthorized
Cause: Missing or invalid authentication
Quick fixes:
// Check token exists
console.log(localStorage.getItem("bknd_token"));
// Verify token with /me endpoint
const me = await api.auth.me();
console.log(me.ok ? "Valid" : "Invalid/expired");
Common causes:
- Token not stored (missing
storage: localStoragein Api config) - Token expired (check JWT
expiresconfig) - Wrong auth header format (must be
Bearer <token>) - Cookie not sent (missing
credentials: "include")
Fix pattern:
const api = new Api({
host: "http://localhost:3000",
storage: localStorage, // Required for token persistence
});
403 Forbidden
Cause: Authenticated but insufficient permissions
Quick fixes:
# Check user's role
curl http://localhost:3000/api/auth/me \
-H "Authorization: Bearer <token>"
Common causes:
- Guard not enabled in config
- Role missing required permission
- Entity-specific permission needed
- Row-level policy blocking access
Fix pattern:
auth: {
guard: {
enabled: true,
roles: {
user: {
permissions: [
"data.entity.read",
"data.entity.create", // Add missing permission
]
}
}
}
}
404 Not Found
Cause: Endpoint or record doesn't exist
Quick fixes:
# List available routes
npx bknd debug routes
# List entities
curl http://localhost:3000/api/data
# Check entity name case (must match exactly)
curl http://localhost:3000/api/data/posts # lowercase
Common causes:
- Entity name case mismatch (
Postsvsposts) - Schema not synced (restart server)
- Wrong endpoint path (
/api/auth/loginvs/api/auth/password/login) - Record ID doesn't exist
409 Conflict
Cause: Duplicate value or constraint violation
Quick fixes:
// Check for existing record before create
const exists = await api.data.readOneBy("users", { email });
if (!exists.ok) {
await api.data.createOne("users", { email, ... });
}
Common causes:
- Duplicate unique field value
- User email already registered
- Unique constraint on field
413 Payload Too Large
Cause: File upload exceeds size limit
Fix:
media: {
body_max_size: 50 * 1024 * 1024, // 50MB
}
500 Internal Server Error
Cause: Unhandled server exception
Quick fixes:
# Check server logs for stack trace
# Look for error details in response body
curl http://localhost:3000/api/data/posts 2>&1 | jq .error
Common causes:
- Database connection failed
- Invalid schema configuration
- Unhandled exception in seed/plugin
- Missing environment variable
Common Mistake Patterns
Using em() as EntityManager
Wrong:
const schema = em({
posts: entity("posts", { title: text() }),
});
schema.repo("posts").find(); // Error!
Correct:
// em() is for schema definition only
const schema = em({
posts: entity("posts", { title: text() }),
});
// Use SDK for queries
const api = new Api({ host: "http://localhost:3000" });
await api.data.readMany("posts");
Wrong Auth Endpoint Path
Wrong:
POST /api/auth/login # 404
POST /api/auth/register # 404
Correct:
POST /api/auth/password/login # For password strategy
POST /api/auth/password/register
POST /api/auth/google/login # For Google OAuth
Missing Storage in Api Config
Symptom: Token not persisting, logged out after refresh
Wrong:
const api = new Api({
host: "http://localhost:3000",
});
Correct:
const api = new Api({
host: "http://localhost:3000",
storage: localStorage, // Or sessionStorage
});
Using enum() Instead of enumm()
Wrong:
import { enum } from "bknd"; // Syntax error - reserved word
Correct:
import { enumm } from "bknd";
entity("posts", {
status: enumm(["draft", "published"]),
});
Using primary() Function
Wrong:
import { primary } from "bknd"; // Not exported in v0.20.0
Correct:
// Primary keys are auto-generated
// To customize format:
entity("posts", { title: text() }, { primary_format: "uuid" });
Wrong Policy Variable Prefix
Wrong:
permissions: [{
permission: "data.entity.read",
filter: { user_id: { $eq: "@user.id" } }, // Wrong prefix
}]
Correct:
permissions: [{
permission: "data.entity.read",
filter: { user_id: { $eq: "@auth.user.id" } }, // Correct prefix
}]
Memory Database for Persistent Data
Symptom: Data disappears on restart
Wrong:
npx bknd run --memory
# Or config: { url: ":memory:" }
Correct:
npx bknd run --db-url "file:data.db"
# Or config: { url: "file:data.db" }
Missing Guard Enable
Symptom: Permissions not working, everyone has access
Wrong:
auth: {
guard: {
roles: { ... } // Guard not enabled!
}
}
Correct:
auth: {
guard: {
enabled: true, // Required!
roles: { ... }
}
}
CORS Cookie Issues
Symptom: Auth works in Postman but not browser
Fix:
// Server config
server: {
cors: {
origin: ["http://localhost:5173"],
credentials: true,
}
}
auth: {
cookie: {
secure: false, // false for HTTP dev
sameSite: "lax", // Not "strict" for OAuth
}
}
// Client fetch
fetch(url, { credentials: "include" });
Filter vs Allow/Deny Effect
Symptom: RLS filter returns all records instead of filtering
Wrong:
permissions: [{
permission: "data.entity.read",
effect: "allow", // Won't filter!
condition: { user_id: { $eq: "@auth.user.id" } },
}]
Correct:
permissions: [{
permission: "data.entity.read",
effect: "filter", // Filters results
filter: { user_id: { $eq: "@auth.user.id" } },
}]
Quick Diagnostic Commands
Check Server Health
curl http://localhost:3000/api/data
List All Routes
npx bknd debug routes
Check Config Paths
npx bknd debug paths
Test Auth
# Login
curl -X POST http://localhost:3000/api/auth/password/login \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"password"}'
# Check token
curl http://localhost:3000/api/auth/me \
-H "Authorization: Bearer <token>"
Test Entity Access
# Unauthenticated
curl http://localhost:3000/api/data/posts
# Authenticated
curl http://localhost:3000/api/data/posts \
-H "Authorization: Bearer <token>"
Check Schema
curl http://localhost:3000/api/system/schema
Environment-Specific Issues
Development
| Issue | Solution |
|---|---|
| Config not loading | Check file name: bknd.config.ts |
| Port in use | npx bknd run --port 3001 |
| Types outdated | npx bknd types |
| Hot reload not working | Restart server |
Production
| Issue | Solution |
|---|---|
| JWT errors | Set JWT_SECRET env var (32+ chars) |
| Cookie not set | secure: true for HTTPS |
| 500 errors | Check logs, set NODE_ENV=production |
| D1 not found | Check wrangler.json bindings |
Serverless
| Issue | Solution |
|---|---|
| Cold start slow | Use edge-compatible DB (D1, Turso) |
| File upload fails | Use S3/R2, not local storage |
| SQLite native error | Use LibSQL or PostgreSQL |
Symptom-Based Troubleshooting
"Config file could not be resolved"
# Check file exists
ls bknd.config.*
# Specify explicitly
npx bknd run -c ./bknd.config.ts
"EADDRINUSE: address already in use"
# Find process
lsof -i :3000
# Use different port
npx bknd run --port 3001
"spawn xdg-open ENOENT"
# Headless server - disable browser open
npx bknd run --no-open
"Data disappears after restart"
# Check for memory mode in output
# Use file database
npx bknd run --db-url "file:data.db"
"ERR_UNSUPPORTED_ESM_URL_SCHEME" (Windows)
- Use Node.js 18+
- Add
"type": "module"to package.json - Use
.mjsextension for config
"TypeError: X is not a function"
Check import paths:
// SDK client
import { Api } from "bknd/client";
// Schema builders
import { em, entity, text } from "bknd";
// Adapters
import { serve } from "bknd/adapter/node"; // Node
import { serve } from "bknd/adapter/cloudflare"; // CF Workers
DOs and DON'Ts
DO:
- Check server logs first
- Verify entity names are lowercase
- Test with curl before debugging frontend
- Restart server after schema changes
- Use
npx bknd debug routesfor 404s
DON'T:
- Use
em()for runtime queries - Use
:memory:for persistent data - Forget
storage: localStoragein Api - Skip
enabled: truefor guard - Use
@user.id(use@auth.user.id)
Related Skills
- bknd-debugging - Comprehensive debugging guide
- bknd-local-setup - Initial project setup
- bknd-setup-auth - Authentication configuration
- bknd-assign-permissions - Permission configuration
- bknd-api-discovery - Explore available endpoints
More from cameronapak/bknd-skills
bknd-login-flow
Use when implementing login and logout functionality in a Bknd application. Covers SDK authentication methods, REST API endpoints, React integration, session checking, and error handling.
16bknd-session-handling
Use when managing user sessions in a Bknd application. Covers JWT token lifecycle, session persistence, automatic renewal, checking auth state, invalidating sessions, and handling expiration.
15btca-bknd-repo-learn
Use btca (Better Context App) to efficiently query and learn from the bknd backend framework. Use when working with bknd for (1) Understanding data module and schema definitions, (2) Implementing authentication and authorization, (3) Setting up media file handling, (4) Configuring adapters (Node, Cloudflare, etc.), (5) Learning from bknd source code and examples, (6) Debugging bknd-specific issues
15bknd-file-upload
Use when uploading files to Bknd storage. Covers MediaApi SDK methods (upload, uploadToEntity), REST endpoints, React integration with file inputs, progress tracking with XHR, browser upload patterns, and entity field attachments.
15bknd-deploy-hosting
Use when deploying a Bknd application to production hosting. Covers Cloudflare Workers/Pages, Node.js/Bun servers, Docker, Vercel, AWS Lambda, and other platforms.
14bknd-bulk-operations
Use when performing bulk insert, update, or delete operations in Bknd. Covers createMany, updateMany, deleteMany, batch processing with progress, chunking large datasets, error handling strategies, and transaction-like patterns.
14