Liking cljdoc? Tell your friends :D

Debugging

General approach

Start from the innermost layer (core/database) and work outward to HTTP. Don’t debug through the full stack when you can isolate the issue.

1. Check logs

tail -100 logs/app.log | grep -A 10 "ERROR"

Errors are logged with stack traces. Look for the first non-Wagoe frame in the trace.

2. Add temporary logging

;; Output appears in REPL/server stdout, not log files
(println "DEBUG:" {:field value :other other-value})

Remove all println statements before committing.

3. Test via REPL

Bypass the HTTP layer and call services directly:

(def user-svc (get integrant.repl.state/system :wagoe/user-service))
(ports/find-user-by-email user-svc "alice@example.com")

4. Inspect HTTP requests

Add temporary logging in handlers:

(println "DEBUG request:"
         {:method  (:request-method request)
          :params  (:params request)
          :headers (select-keys (:headers request) ["hx-request" "authorization"])})

5. Query the database directly

(def ds (get-in integrant.repl.state/system [:wagoe/db-context :datasource]))
(require '[next.jdbc :as jdbc])
(jdbc/execute! ds ["SELECT * FROM users WHERE email = ?" "alice@example.com"])

Common problems and solutions

nil where a field value is expected

Cause: snake_case / kebab-case mismatch.

Check: is the field :password_hash (snake) where the code expects :password-hash (kebab)?

Fix: always use cc/snake-case→kebab-case-map at the persistence boundary.

reset didn’t pick up changes

Cause: You changed a defrecord.

Fix:

(halt)
(go)

HTTP 500 with "Exception reached HTTP boundary without :type in ex-data"

Cause: An ex-info without :type, or an unwrapped Java exception.

Fix: wrap in try-catch with a typed error:

(try
  (UUID/fromString id-string)
  (catch IllegalArgumentException _
    (throw (ex-info "Invalid UUID" {:type :validation-error :value id-string}))))

An error response carries a BND code — where does it come from?

In dev, an error over HTTP answers with a dev block:

{"error": "validation-error",
 "message": "Request validation failed",
 "details": {"email": ["missing required key"]},
 "dev": {"code": "BND-201",
         "category": "validation",
         "docs-url": "bb guide error BND-201"}}

Three things have to be true for that block to appear, and each is deliberate:

  • :wagoe/dev-error-enricher {} is in the :active section of the config — wagoe new writes it into the dev config and nowhere else;

  • the profile the app booted with is dev-like (:dev, :test) — the profile, not an environment variable the deployment may never have been given;

  • wagoe-devtools is on the classpath, and it lives in the :repl alias — so clojure -M:run, the uberjar and the Docker image cannot produce it.

Production gets the same response without the dev block, and its details name only the fields that were wrong. The full messages describe the schema — "should be either \"admin\" or \"auditor\"" hands a caller every enum member it never knew about — so they are dev-only too. A 5xx says "Internal Server Error" and nothing else; the message, the class and the ex-data go to the log, keyed by correlation ID. Delete the config key to see the production shape while developing.

One thing this response does not go through: a coercion failure is answered before the interceptor stack runs, so it carries a correlation ID but not the security headers, and it is not counted by request metrics or the rate limiter.

SQL error: unknown column name

Cause: Schema and database migration are out of sync.

Fix: check that the field exists in both schema.clj, the migration SQL, and shell/persistence.clj.

Tests fail with unbalanced parentheses

Fix:

clj-paren-repair <file-with-issue>

Auth tests fail with "JWT secret not found"

Fix:

JWT_SECRET="dev-secret-at-least-32-characters-long" clojure -M:test :user

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close