Troubleshooting

A symptom-first guide. Each section walks from "what you're seeing" to the most likely cause and how to confirm it.

For per-error details, also see Error codes. For the full troubleshooting flow chart, the Quickstart and the Architecture overview are useful reference companions.

Install and startup

The container exits immediately after docker run
  • Check the container logs first: docker logs curiosity.
  • A missing or unwritable storage path is the most common cause. Confirm the directory you mounted exists on the host and is writable by the user the container runs as:
docker run --rm -v ~/curiosity/storage:/data alpine ls -la /data
  • If the logs say "license required", set MSK_LICENSE.
  • If the logs say "port already in use", another process is bound to 8080. Map a different host port with -p 127.0.0.1:9000:8080.
  • If the logs say "Failed to create the admin account", see the next section. ===
The logs say Failed to create the admin account: MSK_ADMIN_PASSWORD … is set, but MSK_ADMIN_USER and MSK_ADMIN_EMAIL are missing
  • MSK_ADMIN_PASSWORD (or MSK_ADMIN_PASSWORD_FILE) only works together with MSK_ADMIN_USER and MSK_ADMIN_EMAIL. The message names the ones that are missing. Set them and start again.
  • If you did not mean to seed an account — for example the variable is left over from the first start and accounts are now managed in the UI — clear MSK_ADMIN_PASSWORD instead. Existing accounts are left untouched.
  • Seeding runs on every start, not only the first: while all three are set, that account's password, roles and preferences are rewritten to match the variables. See How the admin account is seeded. ===
The Windows service does not start (error 1053, 1064 or 1069)
  • Re-run configure-windows-service.bat from the install folder in an elevated Command Prompt (it refuses to run from PowerShell). It reports MSK_* variables that exist only for your user or console — the service sees machine-scope variables only — and checks every folder the service will use for a network path, a location inside a user profile, missing write access and a missing SYSTEM entry. It recreates the service as LocalSystem, so re-apply a service account afterwards with sc.exe config.
  • 1053 ("did not respond in time") means the process exited before registering with the Service Control Manager, or --MSK_RUN_AS_SERVICE=true is missing from the service command line (sc.exe qc curiosity). 1064 ("exception in the service") means it registered and then failed while starting. For both, look for error.log in the log folder, next to curiosity.exe, or in the temp folder — the workspace writes it to the first of those it can — and for .NET Runtime entries in the Application event log.
  • error.log saying Failed to create the admin account means MSK_ADMIN_PASSWORD is set at machine scope without MSK_ADMIN_USER and MSK_ADMIN_EMAIL — see the entry above. The script does not check the admin variables, so set all three yourself.
  • 1069 ("logon failure") means the account name is wrong (a gMSA needs the trailing $ and an empty password) or the account lacks Log on as a service. sc.exe does not grant that right; secpol.msc or the services.msc UI does.
  • The full list of codes is in Running as a Windows Service.
  • Binaries or data under another user's C:\Users\<name> profile is the most common cause of both — see Windows installation. ===
The UI loads but I can't sign in as admin/admin
  • You probably set MSK_ADMIN_PASSWORD on first boot. The password is whatever value you provided in that variable.
  • If you don't remember it, you can reset it: stop the container, restart it with a new MSK_ADMIN_PASSWORD (together with MSK_ADMIN_USER and MSK_ADMIN_EMAIL), then sign in. The variables are applied on every start, so a password you change in the UI is overwritten at the next restart until you update MSK_ADMIN_PASSWORD to match or clear it.
  • If SSO is configured and admin is disabled, sign in via your IdP instead. ===
The UI is reachable on localhost but not from elsewhere on the network
  • Local installations on this site bind the container port to 127.0.0.1 intentionally. Remove the loopback prefix when you want network reachability — but only after completing the security baseline:
-p 0.0.0.0:8080:8080
  • Or, better, put the workspace behind a reverse proxy that terminates TLS. ===
Restarting the container loses my data
  • Your volume is not mounted, or MSK_GRAPH_STORAGE points outside the mount.
  • Confirm the mount: docker inspect curiosity and look at Mounts.
  • Confirm the env var: docker exec curiosity env | grep MSK_GRAPH_STORAGE.
  • If both look right, the workspace is writing to the persisted path; docker volume ls and the host directory should both grow over time. ===

Ingestion and graph

The connector reports success but I see no data in the UI
  • The connector probably didn't call await graph.CommitPendingAsync() at the end.
  • The connector might have committed to a different workspace — verify the endpoint and token passed to Graph.Connect match the workspace you're inspecting.
  • Look at Settings → Tasks for an error on the most recent run. ===
I'm getting duplicate nodes
  • Almost always a key problem. Confirm each node type has a stable [Key] from the source and that you're not regenerating it (e.g., from a randomly ordered list).
  • Look at the Graph Model → keys section.
  • Quick check in the Shell:
return Q().StartAt(N.Ticket.Type).Where(n => n.GetString("Id") == "T-9182").Take(5).Emit("N");

Should return one node, not many.

Edges are missing between nodes I just ingested
  • Both endpoint nodes must exist before you create the edge. If you call graph.Link(a, b, ...) before either a or b is committed, the edge is queued against a placeholder.
  • Verify with Q().StartAt(N.Ticket.Type, "T-1").Out().Emit("N") and compare to what you expected. ===
schema_conflict on commit
  • You changed a key field's type or removed it. The graph cannot rewrite identity in place. See Upgrades and migrations for the migration pattern. ===

Search and embeddings

Search returns nothing for terms that are clearly in the data
  • The field is not indexed. Open Settings → Search → Indexes and confirm the field appears under the right node type.
  • The field is indexed but the workspace hasn't reindexed since the field was added. Trigger Settings → Maintenance → Rebuild indexes.
  • Permissions are filtering everything out. Sign in as admin and re-run — if results appear, you have a ReBAC problem, not a search problem. See Access Control Model. ===
Vector search returns nothing
  • The embedding provider isn't configured or is failing. Open Settings → AI Settings and check the provider status banner.
  • The embeddings have not been generated yet for older content. Trigger Rebuild embeddings under Settings → Maintenance.
  • The chunking is set too small or too large. See Vector Search. ===
Hybrid search underperforms pure text search
  • The field weights and similarity cutoff need tuning. Walk the Ranking Tuning workflow with a golden query set.
  • For short identifier searches (ticket IDs, SKUs), reduce the vector contribution or fall back to text-only. ===

Custom endpoints and AI tools

My endpoint won't save (compile error)
  • The error is shown in the endpoint editor's status bar. Common offenders: missing using directives, typos in node/edge names, mismatched types in ParseBody<T>().
  • The previous successful version of the endpoint stays live until the new one compiles, so user traffic isn't affected. ===
My endpoint returns 403 for some users
  • The endpoint is running CreateSearchAsync (admin context) instead of CreateSearchAsUserAsync(..., CurrentUser, ...). Switch to the user-context variant.
  • The user really doesn't have access. Verify their team membership and the ACLs on the affected nodes. ===
The AI assistant doesn't call my tool
  • Check the [Tool("...")] description: it should clearly state when the LLM should pick this tool. Vague descriptions don't get selected.
  • The tool may be present but disabled for this chat. Look under the chat's tool list.
  • If multiple tools cover the same intent, the LLM may be picking a different one. Make the descriptions more specific. ===

Authentication and SSO

SSO redirect loops or "invalid redirect URI"
  • The redirect URI registered with your IdP must exactly match {public-workspace-url}/api/{provider}sso/completed-login-attempt. Check for trailing slashes, http vs https, and the MSK_PUBLIC_ADDRESS setting.
  • Verify with curl -I https://workspace.example.com/api/microsoftsso/get-login-url — a working setup returns a 200 with a JSON body containing the IdP URL. ===
All my tokens stopped working after a restart
  • MSK_JWT_KEY changed between restarts, which invalidates every issued token. Set MSK_JWT_KEY explicitly so the key is stable. There is no MSK_JWT_KEY_FILE — read a mounted secret into the variable instead. ===

Operations

Indexing is slow / the workspace appears unresponsive during large imports
  • Move the index rebuild to off-hours and watch progress under Settings → Monitoring.
  • Increase the container's CPU and memory limits. The graph engine is memory-resident; more RAM directly improves traversal latency. See Performance Tuning.
  • Run incremental ingestion instead of full refreshes. See Ingestion Pipelines. ===
Disk usage is growing faster than expected
  • The journal directory grows during bursts of writes and trims afterward. If it doesn't trim, increase your sample window before assuming a leak.
  • Backups in MSK_GRAPH_BACKUP_FOLDER rotate based on retention settings — confirm the retention policy isn't disabled.
  • Logs at MSK_LOG_PATH with MSK_LOG_LEVEL=Debug can fill a disk quickly. Reset to Information once you've finished diagnosing. ===

Still stuck?

© 2026 Curiosity. All rights reserved.
Powered by Neko