Skip to content
Troubleshooting

Troubleshooting

Every message below is copied from the code. Server messages reach the app as the gRPC status message, and the app shows them as they are rather than as a raw error. Log lines go to the pod’s stdout.

Sign-in and sessions

MessageCodeCause and fix
luna has no allowed accounts configured (LUNA_OWNER_EMAIL unset)FailedPreconditionThe allowlist is empty, so every login is rejected. Set LUNA_OWNER_EMAIL.
google sign-in not configured: google sign-in not configured (LUNA_GOOGLE_CLIENT_ID unset)FailedPreconditionSet LUNA_GOOGLE_CLIENT_ID.
this account is not on this luna instance's allowlistPermissionDeniedA valid Google account that isn’t on the list.
google email not verified / invalid google tokenUnauthenticatedA token problem on the user’s side.
cannot reach Google to verify this sign-in — this is a server-side connectivity problem, not a problem with your account: …UnavailableThe backend can’t reach Google’s keys. Check egress on 443.
authorization token is not providedUnauthenticatedThe request had no Bearer token.
invalid token: …UnauthenticatedAn unknown, expired or revoked session. The app signs out and returns to the login screen.
session email is not on this luna instance's allowlistPermissionDeniedThe account was removed from the list. Its sessions are revoked.
luna's session store is unavailableUnavailableThe appfs root couldn’t be mounted, usually because CORE_ENVELOPE_KEK is missing. The server can’t check anything, so the caller’s token is not the problem.

Chat and the model

MessageCause
Luna's own inference server could not be reached. This is not a queue — the model plane is down or not yet configured.Connection refused or no route. Check INFERENCE_REMOTE_URL and the plane.
the model plane is busy right now — every slot on the shared inference server is in use. Try again in a moment.The plane answered 429 or 503, or reported being full.
the model did not answer in time. It is running, but this request took longer than Luna is willing to wait.The deadline was exceeded (DeadlineExceeded). The chat deadline is 6 minutes.
Luna could not complete that generation. The reason is in the server log; it was not a queue and not a timeout.Anything else. Read the pod log.
We've talked a lot this hour and the thinking plane is shared — give me about N minutes and ask again. Logging habits and your plans still work instantly.The hourly chat cap (LUNA_CHAT_TURNS_PER_HOUR, default 30) was reached. This refusal is not journaled.
Boot log: no INFERENCE_REMOTE_URL set — chat will fail until the inference plane is configuredChat isn’t configured.
Boot log: chat tier UNAVAILABLE at <url> after <d>: … — the client stays registered, so requests will still be attempted and will fail slowly rather than fastThe plane didn’t come up. … tier ready at <url> (model loaded in <d>) is the healthy line.

In the app, Luna is unreachable — check your connection and try again. means the request never got an answer from the backend.

Request failed with status: 0 in the browser, together with context canceled in the server log, is a transport kill: a mobile NAT, a carrier middlebox or the browser dropped a response that stayed silent too long. Every RPC that waits on the model streams and re-sends a heartbeat beat every 15 seconds for exactly this reason. If you see it, look for an RPC that waits on the model without streaming. Don’t assume the inference plane is down.

Vision

MessageCause
my eyes aren't wired to a vision model yet — the platform needs its vision tier online for thisLUNA_VISION_REMOTE_URL is unset (FailedPrecondition). The text model can’t see images, so there is deliberately no fallback.
vision is rate-limited on the shared plane — try again in ~N minThe hourly vision cap (default 12) was reached.
N photos is more than I can look at in one go — send up to 3 at a timeMore than 3 images in one request. The app batches for you. Lowering the server cap without shipping a new app build makes every batch fail.

Voice

MessageCause
voice transcription not configured (VOXTRAL_REMOTE_URL unset)STT isn’t configured. The app falls back to the device recogniser.
text-to-speech not configuredTTSD_URL is set to "". The app falls back to on-device TTS.
voice transcription is rate-limited on the shared plane — try again in ~N min / voice is rate-limited on the shared plane — try again in ~N minThe hourly voice cap (default 120) was reached.
Boot log: voice output DEGRADED: ttsd unreachable at <url> after <d> (<n> attempts): …ttsd never answered its health probe during the retry window. The healthy line is voice output: ttsd ready at <url>. The probe is advisory and gates nothing.
Boot log: voice output disabled (TTSD_URL empty) — clients use on-device TTSServer speech was turned off on purpose.

An unreachable ttsd is invisible to users, because the app quietly falls back to the device voice. That is why the boot probe logs its result.

Storage and memory

Log event or messageCause
object_store_not_configured: “OBJECTSTORE_ENDPOINT unset and no LUNA_APPFS_DIR; journals, plans and avatars cannot persist”No storage at all. Nothing persists.
appfs_local_root_onlineNo object store, but LUNA_APPFS_DIR names a real directory, which then holds everything (local development).
object_store_recoveredA background retry succeeded. This is normal shortly after a pod restart.
object_store_still_down: “…a Secret this pod cannot resolve (CORE_ENVELOPE_KEK, OBJECTSTORE_ACCESS_KEY/SECRET_KEY) fails here exactly like an unreachable objectd, and no retry clears it”This is no longer transient. Read the logged error first. A missing Secret looks exactly like a network fault.
“the at-rest encryption key (CORE_ENVELOPE_KEK) is not configured, and the object store refuses to open a store whose contents it cannot seal”The KEK is missing.
no account on this request — Luna's storage is per-account and will not read or write without oneThe data layer refused an unscoped request. This fails closed by design.
A reply marked “not saved” (not_persisted)The journal write failed or timed out (bounded at 5 s). The reply was delivered, but it won’t be remembered.
memory: semantic recall INACTIVE: …No embedding tier (LUNA_EMBED_URL unset or unreachable). Memory falls back to keyword search only.
refusing to start: EMBEDDING_FORMAT: …An unknown embedding format. The server won’t open a memory index in a vector space nobody configured.

Startup refusals

MessageCause
luna: N outbound endpoint(s) would carry personal data in cleartext off this cluster: followed by a listAn outbound URL points off-cluster over plaintext. Every bad endpoint is listed, so you can fix the manifest in one pass.
admission config: …LUNA_ADMIT_MAX or LUNA_ADMIT_QUEUE isn’t a valid number.

Coaching preconditions

MessageCause
design a training plan first — meal targets are derived from the training week, so the two agree.DraftMealPlan was called with no active training plan.
I need your body mass in kg first — every target is anchored to it, and guessing would give you numbers computed for someone else.There is no body mass on the request or in the profile.
level N costs C points — you have B. Keep the streaks alive.LevelUp was called with too few points.
a daily steps goal needs to be between 1,000 and 100,000SetStepsGoal was out of range.

For step-sync messages in the app, see Habits and streaks.