- Docs
- Operate
- FAQ and troubleshooting
FAQ and troubleshooting
Quick answers to the questions that come up most, and a symptom-to-fix list for configuration, adapters, jobs, and the CLI.
Short answers first, then a symptom-to-fix list. Every battery guide also ends with its own troubleshooting section; this page covers the cross-cutting problems.
Does Zever write my business logic?
No. It compiles .zen schemas into infrastructure only: database access, caching, queues, routing, and the other batteries. Your handlers, services, and rules are plain Go you own. See Customizing and leaving for how to step off the generated code.
How do I swap an adapter, say sqlite for postgres?
Change adapter via DB_ADAPTER=postgres env or zever add db/postgres. The adapter must be registered; zever add db/postgres does the go.mod require, the Register() call, and the config stanza. No code that uses the db.DB interface changes. See Choosing batteries.
What is the difference between the queue, the event bus, and the outbox?
The queue is durable work for one consumer to pop, ack, and retry. The event bus is live fan-out with no durability for offline handlers. The outbox records an event inside your database transaction and delivers it at least once. See the background jobs overview.
Do I need Redis?
Not to start. The memory and sqlite defaults need nothing. You need a shared backend (Redis, or the db adapters on your database) once more than one process must see the same cache, queue, session, lock, or rate-limit state.
Is it safe to run zever tinker against production?
No. tinker evaluates arbitrary Go against a live container, is development-only, and prints a warning to stderr before it runs. Never point it at production data.
Can I run Zever without the CLI?
Yes. The runtime packages (config, container, core/*, adapters/*) do not import the compiler. The CLI is for scaffolding, compiling schemas, and operating projects; generated code and the runtime build with plain go build.
How do I turn on shell completion?
zever completion bash|zsh|fish|powershell prints the script; see Shell completion. It completes .zen files, generate kinds, --backend, --profile, and --adapters.
How do I get a heap or CPU profile from a running server?
Start the generated server with --pprof-addr 127.0.0.1:6060 (or PPROF_ADDR); it is off by default and loopback-only. See Profiling with pprof.
Troubleshooting
Section titled “Troubleshooting”Configuration
Section titled “Configuration”Startup fails with “unknown field” or “unknown service”
config.Load decodes strictly, so a typo or a removed key fails fast instead of being ignored. Check spelling (file keys are snake_case, such as max_conns) against the config reference and zever config show.
An environment variable has no effect
Env matching is best-effort by design: a variable that does not match a resolved field is silently ignored, so a noisy environment cannot break startup. Names have no prefix and follow <SERVICE>_<FIELD>, for example DB_MAXCONNS=20 or AUTH_JWT_SECRET=...; case and underscores inside the field are ignored. A value that does match but cannot be parsed is an error. Layering is defaults < file < env.
It connects to sqlite even though I configured postgres
The file was not found. In production, load an explicit path.
Auth fails to open with a short or missing JWT secret
The jwt adapter needs a secret of at least 32 bytes and config.Default() ships none. Set AUTH_JWT_SECRET. The default dev crypto key is public and deterministic: never ship it.
Adapters and the container
Section titled “Adapters and the container”An unknown or unregistered adapter error at startup
The adapter’s package was never imported and its Register() never called. zever add <battery>/<adapter> wires both. The generated server validates every enabled battery at boot and reports the missing ones with did-you-mean hints; zever doctor shows the same per battery.
zever doctor reports FAIL for one battery
The battery is enabled but cannot resolve from the current config: a missing secret, an unreachable DSN, or an adapter that is not registered in the process running the check. Read the error text, fix the option, and re-run. Doctor only checks batteries enabled in your project config.
A test leaves goroutines running
Close the container: c.Close(ctx) stops only the services you resolved, in dependency order. In tests use t.Cleanup, or zevertest.NewTestContainer which does it for you. Note that t.Context() is already canceled inside cleanups, so close with a fresh bounded context.
Schemas and codegen
Section titled “Schemas and codegen”zever compile –check fails with drift
The committed output no longer matches the schema. Regenerate with zever compile and commit the result. A differing CLI version in the stamp alone is only a note, not drift.
The formatter refuses my file
zever fmt will not rewrite a file with lexical errors (an unterminated string, for example). Fix the error first; zever check reports it with a position.
Background work
Section titled “Background work”A dispatched job never runs
Almost always a topic mismatch between the job’s priority and the topics the worker polls, or a memory queue split across processes. See Scheduler and jobs.
Pop returns an empty error
queue.ErrEmpty means the topic has nothing ready; it is not a failure. Handle it and poll again.
Messages are processed twice
Queues and the outbox deliver at least once, and an un-acked message reappears after the visibility timeout. Make the consumer idempotent with the idempotency battery or the outbox Inbox, and ack promptly.
Still stuck?
Section titled “Still stuck?”Run zever doctor and zever config show (secrets are redacted), then open an issue with the output. Keep raw option maps out of logs and bug reports: print only what config.RedactedServices returns.