Back to list
cameronapak

bknd-troubleshoot

by cameronapak

A no-build, un-bloated stack built upon Web Standards that feels freeing to use and can be deployed anywhere.

23🍴 2📅 Jan 21, 2026

SKILL.md


name: bknd-troubleshoot description: Use when encountering Bknd errors, getting error messages, something not working, or needing quick fixes. Covers error code reference, quick solutions, and common mistake patterns.

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/json header
  • 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: localStorage in Api config)
  • Token expired (check JWT expires config)
  • 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 (Posts vs posts)
  • Schema not synced (restart server)
  • Wrong endpoint path (/api/auth/login vs /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: { ... }
  }
}

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

IssueSolution
Config not loadingCheck file name: bknd.config.ts
Port in usenpx bknd run --port 3001
Types outdatednpx bknd types
Hot reload not workingRestart server

Production

IssueSolution
JWT errorsSet JWT_SECRET env var (32+ chars)
Cookie not setsecure: true for HTTPS
500 errorsCheck logs, set NODE_ENV=production
D1 not foundCheck wrangler.json bindings

Serverless

IssueSolution
Cold start slowUse edge-compatible DB (D1, Turso)
File upload failsUse S3/R2, not local storage
SQLite native errorUse 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)

  1. Use Node.js 18+
  2. Add "type": "module" to package.json
  3. Use .mjs extension 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 routes for 404s

DON'T:

  • Use em() for runtime queries
  • Use :memory: for persistent data
  • Forget storage: localStorage in Api
  • Skip enabled: true for guard
  • Use @user.id (use @auth.user.id)
  • 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

Score

Total Score

75/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

+10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon