Skip to content

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.

SymptomProblemSection
Pods restarting, RESTARTS climbingCrashLoopBackOffProblem 1
Deploy succeeded but returns 502/504Wrong bind addressProblem 2
Build fails before deployDockerfile errorProblem 3
App can’t read env vars or secretsConfig not reloadedProblem 4
Wrong app got updatedWrong --config pathProblem 5
”app X not found” errorWrong org or profileProblem 6

Problem 1: Pod Keeps Restarting (CrashLoopBackOff)

Section titled “Problem 1: Pod Keeps Restarting (CrashLoopBackOff)”
Terminal window
1ctl deploy get

Expected output:

Deployment Details
──────────────────
Deployment ID: 7f1fab9e-5f87-4612-b306-3da846b95d18
Status: failed
URL: https://happyotter-x3k9m2.satusky.com
Type: production
Port: 8080
CPU Request: 0.5
Memory Request: 256Mi

A 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:

Terminal window
1ctl deploy status
Status: CrashLoopBackOff
Message: Back-off restarting failed container
Progress: 0%

Stream logs immediately. The crash message appears in the last lines printed before the process exits:

Terminal window
1ctl logs stream

Expected output:

2026-04-27T10:00:08Z [my-api] Initializing application...
2026-04-27T10:00:08Z [my-api] panic: DATABASE_URL environment variable not set
2026-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 +0x58
2026-04-27T10:00:08Z [my-api] exit status 2
2026-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 set

The same crash repeats every restart cycle. You have your answer: DATABASE_URL is missing.

  • 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:

Terminal window
1ctl secret create --kv DATABASE_URL=postgres://api-user:[email protected]:5432/myapp?sslmode=require

Expected output:

✅ Secret my-api created successfully

The running (crashing) pod doesn’t have the secret yet. Deploy to start a new pod with the updated environment:

Terminal window
1ctl deploy --wait

Then stream logs to confirm a clean startup:

Terminal window
1ctl logs stream

Expected output:

2026-04-27T10:05:14Z [my-api] Connected to database in 38ms
2026-04-27T10:05:14Z [my-api] Listening on 0.0.0.0:8080
2026-04-27T10:05:18Z [my-api] GET /health 200 91µs

Restarts 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”

deploy get shows the deployment healthy, but every HTTP request returns a 502 or 504:

Terminal window
1ctl deploy get
Deployment Details
──────────────────
Status: completed
URL: https://happyotter-x3k9m2.satusky.com
Terminal window
curl -I https://happyotter-x3k9m2.satusky.com
HTTP/2 502

The load balancer can reach your pod but cannot get a response from it.

Stream logs and look at the bind address the process reports:

Terminal window
1ctl logs stream

Expected output:

2026-04-27T10:00:05Z [my-api] Listening on 127.0.0.1:8080

127.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:

Terminal window
1ctl env create --env HOST=0.0.0.0

Expected output:

✅ Environment my-api created successfully

Then redeploy so the new pod picks up the variable:

Terminal window
1ctl deploy --wait

Stream logs to confirm:

Terminal window
1ctl logs stream

Expected output:

2026-04-27T10:08:01Z [my-api] Listening on 0.0.0.0:8080

Verify the fix:

Terminal window
curl -I https://happyotter-x3k9m2.satusky.com
HTTP/2 200

If 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.


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_2k9xm1r4p7
Step 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 1

The deploy aborts. No new image was pushed, no deployment was updated.

The error is in the streamed output — there is no separate log to fetch. Read the output carefully. Common causes:

  • Bad package versiontorch==99.0.0 doesn’t exist; check PyPI for the correct version
  • Wrong COPY path — the file doesn’t exist at the path specified, or .dockerignore excluded it; the COPY step fails with “no such file or directory”
  • Missing system dependency — a RUN step calls a binary (gcc, libgomp1) that isn’t installed in the base image
  • Wrong --from stage name — a multi-stage COPY --from=builder refers 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.0
uvicorn[standard]==0.30.1
torch==2.3.0
transformers==4.41.2

Then redeploy:

Terminal window
1ctl deploy --wait

Kaniko 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”

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 disabled

Confirm the key actually exists:

Terminal window
1ctl secret list

Expected output:

NAME SECRET ID DEPLOYMENT ID CREATED
my-api bcbeb9d7-958c-4aa6-b1a1-51846504cfe8 7f1fab9e-5f87-4612-b306-3da846b95d18 just now
Terminal window
1ctl env list

Expected output:

NAME ENV ID DEPLOYMENT ID CREATED
my-api 798cf7bc-a85a-45b9-9a91-720e3fcade62 7f1fab9e-5f87-4612-b306-3da846b95d18 just now

The 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:

Terminal window
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:

Terminal window
1ctl deploy restart

Stream logs to confirm the variable is now loaded:

Terminal window
1ctl logs stream

Expected output:

2026-04-27T10:10:02Z [my-api] API_KEY loaded from environment
2026-04-27T10:10:02Z [my-api] Auth enabled
2026-04-27T10:10:02Z [my-api] Listening on 0.0.0.0:8080

When 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.


You ran a deploy, but the wrong application has a fresh timestamp. List recent deploys to find the unexpected activity:

Terminal window
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.

Check the release history for the accidentally updated deployment:

Terminal window
1ctl deploy releases --config ./staging/satusky.toml

Expected output:

VERSION IMAGE STATUS DEPLOYED
4 registry.satusky.com/default/staging-api:deploy-1745758923 active just now
3 registry.satusky.com/default/staging-api:deploy-1745700000 superseded yesterday

Version 4 was deployed moments ago — that’s the unintended deploy.

Roll the wrong deployment back to its previous version immediately:

Terminal window
1ctl deploy rollback --config ./staging/satusky.toml --version 3 -y

Expected output:

Roll back deployment staging-api to version 3? This cannot be undone. [y/N] y
✅ Rollback to version 3 initiated

No rebuild — the platform re-runs the previous image immediately. Then deploy the project you actually intended to update:

Terminal window
1ctl deploy --config ./my-api/satusky.toml --wait

The 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.


Terminal window
1ctl deploy status

Expected output:

Error: app "my-api" not found

Three checks in order:

1. Does the app appear in the list?

Terminal window
1ctl deploy list

If 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?

Terminal window
1ctl org current

Expected output:

Current Organization
────────────────────
Organization: staging-org
Organization ID: 690839ba-3aed-47ea-a8ec-0cd019e4d180
Namespace: staging-org-690839ba

If 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?

Terminal window
1ctl profile list

Expected output:

Profiles
────────
* production
API URL: https://api.satusky.com/v1/cli
Org: prod-org
---
staging
API URL: https://api.satusky.com/v1/cli
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:

Terminal window
1ctl profile use production
1ctl org switch prod-org

Then re-run your original command:

Terminal window
1ctl deploy get

Expected output:

Deployment Details
──────────────────
Deployment ID: 7f1fab9e-5f87-4612-b306-3da846b95d18
Status: completed
URL: https://happyotter-x3k9m2.satusky.com

If the app genuinely doesn’t exist — it was deleted, or was never deployed in this org — recreate it:

Terminal window
1ctl deploy --wait

Run these commands in order when a deployment problem isn’t immediately obvious. Each one narrows the scope of the problem.

Terminal window
# 1. Confirm you're on the right profile and org
1ctl profile list
1ctl org current
# 2. Confirm the app exists in this context
1ctl deploy list
# 3. Check deployment details and status
1ctl deploy get
# 4. Read what the process printed before it crashed
1ctl logs stream
# 5. Confirm secrets and env vars are present
1ctl secret list
1ctl env list
# 6. Review release history
1ctl deploy releases

Most problems resolve after step 4. If logs stream shows a clear crash message, fix that first — the other commands are confirmatory.


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:

Terminal window
# 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.