This document is the first-stop troubleshooting guide for the current Go implementation of codex-mem.
Audience:
- operators
- maintainers
- integrators debugging runtime or MCP setup issues
Use this when:
doctorfails or reports unexpected readiness values- config changes do not appear to take effect
- SQLite cannot be opened or migrated
servestarts but an MCP client cannot initialize or call tools
Do not use this for:
- learning what mem is for
- normal day-to-day prompt usage
- release packaging policy decisions
Start with:
go run ./cmd/codex-mem doctorFor scripts or CI:
go run ./cmd/codex-mem doctor --jsonCheck these first:
config_file_useddatabasejournal_modeforeign_keysrequired_schema_okfts_readymigrations_pendingmcp_tool_count
If doctor itself fails, move to the matching section below.
Expected precedence is:
defaults < config file < environment
What to check:
doctorshould show the effectiveconfig_file_usedpath.- If
config_file_used=none, the default file was not loaded. - The default config location is
configs/codex-mem.jsonunder the current working directory. CODEX_MEM_CONFIG_FILEoverrides the default discovery path.
Important behavior:
- If
CODEX_MEM_CONFIG_FILEis relative, it is resolved relative toconfigs/, not the repository root. - If
CODEX_MEM_CONFIG_FILEis absolute, that exact file is used.
Examples:
go run ./cmd/codex-mem doctor$env:CODEX_MEM_CONFIG_FILE="custom.toml"
go run ./cmd/codex-mem doctor$env:CODEX_MEM_CONFIG_FILE="D:\shared\codex-mem.toml"
go run ./cmd/codex-mem doctorLikely causes:
- the path in
CODEX_MEM_CONFIG_FILEdoes not exist - the file format is not valid for its extension
- the file contents are syntactically invalid
What to do:
- Confirm the exact path from
doctoror from the environment variable. - Remove
CODEX_MEM_CONFIG_FILEtemporarily and verify the default path works. - Start from codex-mem.example.json and reapply changes incrementally.
Symptom: startup fails with invalid log_level, invalid busy_timeout_ms, or another invalid ... message
These are validation failures in config parsing.
What to check:
log_levelmust be one ofdebug,info,warn, orerror- numeric settings such as
busy_timeout_ms,log_max_size_mb,log_max_backups, andlog_max_age_daysmust be positive integers - boolean settings such as
log_compressandlog_stderrmust be valid boolean-like strings
Recommended recovery:
- Remove environment overrides one by one.
- Run
doctorafter each change. - Prefer a minimal config file first, then add optional settings back.
The most common cause is an environment override still being set.
Check these variables:
CODEX_MEM_DB_PATHCODEX_MEM_SYSTEM_NAMECODEX_MEM_CONFIG_FILECODEX_MEM_BUSY_TIMEOUT_MSCODEX_MEM_JOURNAL_MODECODEX_MEM_LOG_LEVELCODEX_MEM_LOG_FILE
On PowerShell, inspect current overrides with:
Get-ChildItem Env:CODEX_MEM_*The database layer creates the parent directory automatically before opening SQLite.
Likely causes:
- the configured directory is not writable
- the path points into a protected location
- a parent segment is invalid for the current platform
What to do:
- Check the effective
databasepath fromdoctor. - Move the database under a writable project-local location such as
data/codex-mem.db. - Re-run
go run ./cmd/codex-mem doctor.
These indicate the SQLite handle opened incorrectly or could not become usable.
Likely causes:
- the database file location is invalid or unwritable
- another process is holding the database in a conflicting state
- the configured driver name was changed away from
sqlite
What to check:
sqlite_drivershould normally remainsqlitedatabaseshould point to a valid local path or:memory:journal_modeshould normally beWAL
Recommended recovery:
- Reset to the default
sqlitedriver unless there is a very specific reason not to. - Point
CODEX_MEM_DB_PATHto a fresh local file. - Run
doctoragain and confirm:foreign_keys=truerequired_schema_ok=truefts_ready=truemigrations_pending=0
Use the doctor fields as the decision table:
required_schema_ok=falseThe database opened, but the expected schema objects are missing. Rungo run ./cmd/codex-mem migrateor point back to the intended database file.fts_ready=falseMigrations are incomplete or a different database file is being inspected.migrations_pending>0The current database has not applied all embedded migrations yet.foreign_keys=falseSQLite pragmas did not apply as expected and the runtime should be treated as unhealthy.
By default:
- structured logs go to the configured log file
- logs also go to stderr unless
log_stderr=false
Check:
log_filelog_stderrlog_level
Typical default log location:
logs/codex-mem.log
If serve appears silent, that can be normal on stdout because stdout is reserved for MCP frames.
The Codex/go-sdk-backed stdio transport uses newline-delimited JSON-RPC messages.
What the client must support:
- stdio transport
- newline-delimited JSON-RPC messages for the target Codex-compatible path
- JSON-RPC
2.0 initializetools/listtools/call
If a client sends Content-Length-framed stdio instead of newline-delimited JSON, initialization will fail.
Likely causes:
- the client is not writing exactly one JSON-RPC message per line
- the client is still sending
Content-Length-framed stdio instead of newline-delimited JSON - the client is not sending
jsonrpc: "2.0" - the client is calling unsupported methods
- tool arguments contain unknown fields and are rejected during decode
What to do:
- Confirm the client sends
initializefirst. - Confirm the client writes exactly one JSON-RPC message per line and reads newline-delimited responses.
- Confirm tool calls use the schemas exposed by
tools/list. - If the client is custom, compare it against a known-good initialize and ping flow.
Tool input decoding uses strict unknown-field rejection.
That means:
- misspelled property names fail
- extra properties fail
- wrong JSON types fail
Best recovery path:
- Fetch the live schema from
tools/list. - Trim the request down to only required fields.
- Add optional fields back one at a time.
The HTTP transport is now session-aware.
What to check:
- the first
initializeresponse should include theMcp-Session-Idheader - every later HTTP request in the same logical session should send that same
Mcp-Session-Id - if the client silently drops that header, the server treats the next request as a different session context
Recommended recovery:
- Capture
Mcp-Session-Idfrom the initialize response. - Reuse it on
notifications/initialized,tools/list,tools/call, and optionalGET /mcprequests. - If you are using the go-sdk client transports, prefer them over a hand-written HTTP client so session handling is automatic.
What to check:
GET /mcpmust includeAccept: text/event-streamGET /mcpmust include the activeMcp-Session-Id- the session must already be initialized through
POST /mcp
Typical failure modes:
- missing
Accept: text/event-streamreturns a request-format error - missing session header returns a bad-request or not-found style error
- reusing a dead session id after the client or server closed it returns
session not found
If you are using github.com/modelcontextprotocol/go-sdk, the streamable HTTP client handles the standalone SSE connection automatically after initialization.
Check whether the server was started with --session-timeout.
What it means:
- idle HTTP MCP sessions are closed automatically after that duration
- later requests that reuse the expired
Mcp-Session-Idwill fail because the session no longer exists
Recommended recovery:
- reconnect and run
initializeagain to obtain a freshMcp-Session-Id - increase
--session-timeoutif your client legitimately stays idle for longer periods - leave
--session-timeoutunset if you do not want idle expiry at all
Use doctor to confirm the server-side registration is healthy:
mcp_transport=stdioin text modemcp.tool_count=11in JSON mode
If tool count is lower than expected, treat it as a server construction regression instead of a client problem.
Remove-Item Env:CODEX_MEM_CONFIG_FILE -ErrorAction SilentlyContinue
Remove-Item Env:CODEX_MEM_DB_PATH -ErrorAction SilentlyContinue
Remove-Item Env:CODEX_MEM_SYSTEM_NAME -ErrorAction SilentlyContinue
go run ./cmd/codex-mem doctor$env:CODEX_MEM_DB_PATH="data\troubleshooting.db"
go run ./cmd/codex-mem doctorgo run ./cmd/codex-mem serveExpected result:
- the process stays running
- no human-readable protocol output is printed to stdout
- logs, if enabled, appear in stderr and the configured log file
Move beyond this guide when:
doctorsucceeds but retrieval behavior still looks wrong- the database is healthy but search or bootstrap ranking looks suspicious
- a specific MCP client still fails after stdio framing and schema checks pass
Those cases are more likely to need client-specific examples or richer retrieval and audit traces.