Troubleshooting
All six problems in this guide are diagnosable without leaving the terminal. The pattern is the same every time: read deploy get, stream logs, look at what the process printed before it died or failed.
Quick reference
Section titled “Quick reference”| Symptom | Problem | Section |
|---|---|---|
| Pods restarting, RESTARTS climbing | CrashLoopBackOff | Problem 1 |
| Deploy succeeded but returns 502/504 | Wrong bind address | Problem 2 |
| Build fails before deploy | Dockerfile error | Problem 3 |
| App can’t read env vars or secrets | Config not reloaded | Problem 4 |
| Wrong app got updated | Wrong --config path | Problem 5 |
| ”app X not found” error | Wrong org or profile | Problem 6 |
Problem 1: Pod Keeps Restarting (CrashLoopBackOff)
Section titled “Problem 1: Pod Keeps Restarting (CrashLoopBackOff)”How to spot
Section titled “How to spot”1ctl deploy getExpected output:
Deployment Details──────────────────Deployment ID: 7f1fab9e-5f87-4612-b306-3da846b95d18Status: failedURL: https://happyotter-x3k9m2.satusky.comType: productionPort: 8080CPU Request: 0.5Memory Request: 256MiA failed or stuck status combined with repeated restarts visible in 1ctl deploy status (Status: CrashLoopBackOff) means the container is starting, crashing, and being restarted by Kubernetes on an exponential backoff. The pod is not serving traffic.
For a quick K8s live check:
1ctl deploy statusStatus: CrashLoopBackOffMessage: Back-off restarting failed containerProgress: 0%Diagnose
Section titled “Diagnose”Stream logs immediately. The crash message appears in the last lines printed before the process exits:
1ctl logs streamExpected output:
2026-04-27T10:00:08Z [my-api] Initializing application...2026-04-27T10:00:08Z [my-api] panic: DATABASE_URL environment variable not set2026-04-27T10:00:08Z [my-api] goroutine 1 [running]:2026-04-27T10:00:08Z [my-api] main.main()2026-04-27T10:00:08Z [my-api] /app/main.go:14 +0x582026-04-27T10:00:08Z [my-api] exit status 22026-04-27T10:00:11Z [my-api] container restarting... (backoff: 10s)2026-04-27T10:00:21Z [my-api] Initializing application...2026-04-27T10:00:21Z [my-api] panic: DATABASE_URL environment variable not setThe same crash repeats every restart cycle. You have your answer: DATABASE_URL is missing.
Common causes
Section titled “Common causes”- Missing secret or env var — the most common cause; app panics or exits on startup when a required variable is absent
- App binding to a port other than the one in
satusky.toml— health check fails, pod restarts - Panic or unhandled error during init — database connection refused, config file not found, TLS cert missing
- Binary not found or wrong entrypoint in
CMD
Add the missing variable:
1ctl secret create --kv DATABASE_URL=postgres://api-user:[email protected]:5432/myapp?sslmode=requireExpected output:
✅ Secret my-api created successfullyThe running (crashing) pod doesn’t have the secret yet. Deploy to start a new pod with the updated environment:
1ctl deploy --waitThen stream logs to confirm a clean startup:
1ctl logs streamExpected output:
2026-04-27T10:05:14Z [my-api] Connected to database in 38ms2026-04-27T10:05:14Z [my-api] Listening on 0.0.0.0:80802026-04-27T10:05:18Z [my-api] GET /health 200 91µsRestarts will stop once the new pod stays up. Verify with 1ctl deploy status.
Problem 2: Deployed but App Returns 502/504
Section titled “Problem 2: Deployed but App Returns 502/504”How to spot
Section titled “How to spot”deploy get shows the deployment healthy, but every HTTP request returns a 502 or 504:
1ctl deploy getDeployment Details──────────────────Status: completedURL: https://happyotter-x3k9m2.satusky.comcurl -I https://happyotter-x3k9m2.satusky.comHTTP/2 502The load balancer can reach your pod but cannot get a response from it.
Diagnose
Section titled “Diagnose”Stream logs and look at the bind address the process reports:
1ctl logs streamExpected output:
2026-04-27T10:00:05Z [my-api] Listening on 127.0.0.1:8080127.0.0.1 is the loopback interface — the process only accepts connections from within the same container. The Satusky load balancer connects from outside the container over the pod network, so every request is refused. This is the bind-address problem.
Update your application to bind on 0.0.0.0. For most frameworks you can do this without changing code by passing the host via an environment variable:
1ctl env create --env HOST=0.0.0.0Expected output:
✅ Environment my-api created successfullyThen redeploy so the new pod picks up the variable:
1ctl deploy --waitStream logs to confirm:
1ctl logs streamExpected output:
2026-04-27T10:08:01Z [my-api] Listening on 0.0.0.0:8080Verify the fix:
curl -I https://happyotter-x3k9m2.satusky.comHTTP/2 200If your framework ignores environment variables for the bind host, set it in code: uvicorn app.main:app --host 0.0.0.0, app.listen(8080, '0.0.0.0'), etc.
Problem 3: Cloud Build Fails
Section titled “Problem 3: Cloud Build Fails”How to spot
Section titled “How to spot”1ctl deploy --wait streams the build output, then exits with a non-zero status and an error message inline:
💡 Packaging build context...💡 Submitting build to cloud...💡 Build ID: bld_2k9xm1r4p7Step 1/5: Building image (cloud) my-api ✗Error: build failed — Collecting torch==99.0.0 ... ERROR: Could not find a version that satisfies the requirement torch==99.0.0 ERROR: No matching distribution found for torch==99.0.0 exit code 1The deploy aborts. No new image was pushed, no deployment was updated.
Diagnose
Section titled “Diagnose”The error is in the streamed output — there is no separate log to fetch. Read the output carefully. Common causes:
- Bad package version —
torch==99.0.0doesn’t exist; check PyPI for the correct version - Wrong
COPYpath — the file doesn’t exist at the path specified, or.dockerignoreexcluded it; theCOPYstep fails with “no such file or directory” - Missing system dependency — a
RUNstep calls a binary (gcc,libgomp1) that isn’t installed in the base image - Wrong
--fromstage name — a multi-stageCOPY --from=builderrefers to a stage that was renamed or doesn’t exist
Fix the Dockerfile or requirements.txt based on what the output told you. For a bad package version:
fastapi==0.111.0uvicorn[standard]==0.30.1torch==2.3.0transformers==4.41.2Then redeploy:
1ctl deploy --waitKaniko skips unchanged layers. If only requirements.txt changed, the FROM and any system-dep layers are restored from cache, and only the pip install step re-runs.
Problem 4: Secrets and Env Vars Not Available in the App
Section titled “Problem 4: Secrets and Env Vars Not Available in the App”How to spot
Section titled “How to spot”You ran secret create or env create, but the application logs still report the variable missing:
2026-04-27T10:00:08Z [my-api] WARN: API_KEY is empty — auth disabledDiagnose
Section titled “Diagnose”Confirm the key actually exists:
1ctl secret listExpected output:
NAME SECRET ID DEPLOYMENT ID CREATEDmy-api bcbeb9d7-958c-4aa6-b1a1-51846504cfe8 7f1fab9e-5f87-4612-b306-3da846b95d18 just now1ctl env listExpected output:
NAME ENV ID DEPLOYMENT ID CREATEDmy-api 798cf7bc-a85a-45b9-9a91-720e3fcade62 7f1fab9e-5f87-4612-b306-3da846b95d18 just nowThe secret/env group is there. The problem is timing: secrets and env vars are injected at pod startup. A pod that was already running when you created the variable does not see the new value. The environment inside a running container is frozen at the moment the container started.
To inspect individual keys, use -o json:
1ctl env list -o json | jq '.[0].key_values'Do a rolling restart to replace running pods with fresh ones that pick up the current environment:
1ctl deploy restartStream logs to confirm the variable is now loaded:
1ctl logs streamExpected output:
2026-04-27T10:10:02Z [my-api] API_KEY loaded from environment2026-04-27T10:10:02Z [my-api] Auth enabled2026-04-27T10:10:02Z [my-api] Listening on 0.0.0.0:8080When to use deploy restart vs deploy --wait: use deploy restart when only config changed (secrets, env vars) — no rebuild, fast rolling replacement. Use deploy --wait when you also have code or Dockerfile changes that require a new image.
Problem 5: Wrong Deployment Updated
Section titled “Problem 5: Wrong Deployment Updated”How to spot
Section titled “How to spot”You ran a deploy, but the wrong application has a fresh timestamp. List recent deploys to find the unexpected activity:
1ctl -o json deploy list | jq '.[] | {app_label, status, updated_at}'Expected output:
{ "app_label": "staging-api", "status": "completed", "updated_at": "2026-04-27T11:42:03Z" }{ "app_label": "ml-api", "status": "completed", "updated_at": "2026-04-21T09:15:44Z" }{ "app_label": "my-api", "status": "completed", "updated_at": "2026-04-20T14:33:11Z" }staging-api was just updated — not the intended target.
Diagnose
Section titled “Diagnose”Check the release history for the accidentally updated deployment:
1ctl deploy releases --config ./staging/satusky.tomlExpected output:
VERSION IMAGE STATUS DEPLOYED4 registry.satusky.com/default/staging-api:deploy-1745758923 active just now3 registry.satusky.com/default/staging-api:deploy-1745700000 superseded yesterdayVersion 4 was deployed moments ago — that’s the unintended deploy.
Roll the wrong deployment back to its previous version immediately:
1ctl deploy rollback --config ./staging/satusky.toml --version 3 -yExpected output:
Roll back deployment staging-api to version 3? This cannot be undone. [y/N] y✅ Rollback to version 3 initiatedNo rebuild — the platform re-runs the previous image immediately. Then deploy the project you actually intended to update:
1ctl deploy --config ./my-api/satusky.toml --waitThe root cause is usually running 1ctl deploy from the wrong directory, or a --config flag pointing at the wrong file. Double-check before deploying by running 1ctl deploy get --config <path> first — it shows the app name from that config without making any changes.
Problem 6: “App Not Found” Error
Section titled “Problem 6: “App Not Found” Error”How to spot
Section titled “How to spot”1ctl deploy statusExpected output:
Error: app "my-api" not foundDiagnose
Section titled “Diagnose”Three checks in order:
1. Does the app appear in the list?
1ctl deploy listIf my-api is absent from the list, you’re either in the wrong organization or using the wrong profile. If it appears, something else is wrong with the status command invocation.
2. Which org is active?
1ctl org currentExpected output:
Current Organization────────────────────Organization: staging-orgOrganization ID: 690839ba-3aed-47ea-a8ec-0cd019e4d180Namespace: staging-org-690839baIf this isn’t the org where my-api lives, that’s your problem. Apps are scoped to organizations — my-api in prod-org is invisible while staging-org is active.
3. Which profile is active?
1ctl profile listExpected output:
Profiles────────* production API URL: https://api.satusky.com/v1/cli Auth: [email protected] Org: prod-org--- staging API URL: https://api.satusky.com/v1/cli Auth: [email protected] Org: staging-org---The * marks the active profile. A profile points to a different API endpoint, which may be a different cluster entirely. If you’re on the wrong profile, even the right org won’t have the app you’re looking for.
Switch to the correct profile and org:
1ctl profile use production1ctl org switch prod-orgThen re-run your original command:
1ctl deploy getExpected output:
Deployment Details──────────────────Deployment ID: 7f1fab9e-5f87-4612-b306-3da846b95d18Status: completedURL: https://happyotter-x3k9m2.satusky.comIf the app genuinely doesn’t exist — it was deleted, or was never deployed in this org — recreate it:
1ctl deploy --waitGeneral Debugging Checklist
Section titled “General Debugging Checklist”Run these commands in order when a deployment problem isn’t immediately obvious. Each one narrows the scope of the problem.
# 1. Confirm you're on the right profile and org1ctl profile list1ctl org current
# 2. Confirm the app exists in this context1ctl deploy list
# 3. Check deployment details and status1ctl deploy get
# 4. Read what the process printed before it crashed1ctl logs stream
# 5. Confirm secrets and env vars are present1ctl secret list1ctl env list
# 6. Review release history1ctl deploy releasesMost problems resolve after step 4. If logs stream shows a clear crash message, fix that first — the other commands are confirmatory.
CLI view vs. what’s in Kubernetes
Section titled “CLI view vs. what’s in Kubernetes”1ctl deploy list shows deployment resources that the platform tracks in its database. Older docs may mention 1ctl service list and 1ctl ingress list; those are legacy/manual command surfaces and were not present in the current user-facing CLI help verified for v0.8.3. Resources created outside of 1ctl (via the web dashboard, directly with kubectl, or by marketplace apps) may appear in kubectl get output but not in 1ctl commands.
If you suspect an env var or secret should be set but the pod isn’t seeing it, check two things:
# 1. What the platform DB says the env contains:1ctl env list -o json | jq '.[0].key_values'
# 2. What's actually set on the running Deployment spec (Kubernetes source of truth):kubectl -n <namespace> get deployment <app> \ -o jsonpath='{.spec.template.spec.containers[0].env}'After env create or secret create, the platform patches both the Deployment spec and the underlying ConfigMap/Secret atomically. After env unset or secret unset, the key is removed from both the Deployment spec and the ConfigMap/Secret. If the platform and Kubernetes are out of sync, the most common cause is a stale pod that pre-dates the last env create — run 1ctl deploy restart to replace the pod with one that picks up the current environment.