> ## Documentation Index
> Fetch the complete documentation index at: https://tyk.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Kubernetes Bootstrap Failures

> Troubleshoot Helm bootstrap job failures, pod crash-loops, and inaccessible Admin UI after deploying the Tyk Developer Portal on Kubernetes.

This page covers common failures when deploying the Tyk Developer Portal on Kubernetes. For installation steps and configuration, see [Install Developer Portal on Kubernetes](/portal/install/kubernetes).

## Bootstrap Job Fails: Pod Security Standards Violation

**Symptom:** `helm install` completes but the bootstrap job fails with a security policy error, for example:

```
Error creating: pods "dev-portal-job-..." is forbidden: violates PodSecurity "restricted:latest"
```

**Cause:** The bootstrap job runs as root and does not support security context configuration via `values.yaml`. Clusters enforcing the Kubernetes PSS [Restricted](https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted) or [Baseline](https://kubernetes.io/docs/concepts/security/pod-security-standards/#baseline) profiles will reject it.

**Fix:** Disable the automatic bootstrap job and bootstrap the portal manually:

1. Set `global.components.bootstrap: false` in your `values.yaml` and run `helm upgrade`.
2. Wait for the Portal pod to be ready:
   ```bash theme={null}
   kubectl rollout status deployment/tyk-dev-portal -n <namespace>
   ```
3. Send the bootstrap request to create the bootstrap admin user:
   ```bash theme={null}
   curl -X POST http://<portal-service>:<port>/portal-api/bootstrap \
     -H "Content-Type: application/json" \
     -d '{
       "username": "admin@example.com",
       "password": "your-password",
       "first_name": "Admin",
       "last_name": "User"
     }'
   ```

Once the call succeeds, the Portal shuts down the temporary bootstrap server and completes startup.

<Note>
  This is a known limitation in the Helm chart. The bootstrap job template does not yet support security context configuration. Use `global.components.bootstrap: false` and bootstrap manually as described above.
</Note>

## Portal Pod Crash-Looping

**Symptom:** The Portal pod restarts repeatedly. Inspect the pod state and logs:

```bash theme={null}
kubectl get pods -n <namespace>
kubectl describe pod <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace> --previous
```

### Probe Timeouts: Pod Killed Before Startup Completes

**Symptom:** Kubernetes terminates the pod before it finishes starting. Logs show:

```
Readiness probe failed: HTTP probe failed with statuscode: 503
Liveness probe failed: HTTP probe failed with statuscode: 503
```

**Cause:** The Portal's `/ready` endpoint performs a live database ping on every probe check. Short-lived database latency (TLS handshake overhead or connection pool delays) can cause the probe to time out, triggering Kubernetes to restart the pod before it has fully initialized.

**Fix:** Increase the probe delays and thresholds in your `values.yaml`:

```yaml theme={null}
livenessProbe:
  initialDelaySeconds: 120
  periodSeconds: 10
  timeoutSeconds: 5
  failureThreshold: 3

readinessProbe:
  initialDelaySeconds: 120
  periodSeconds: 10
  timeoutSeconds: 5
  failureThreshold: 3
```

If the Portal connects to a database over a high-latency or TLS-secured link, increase `initialDelaySeconds` further (e.g., `300`).

### PostgreSQL Date Format Mismatch

**Symptom:** The pod enters `CrashLoopBackOff` immediately after starting, even though the database is reachable. Logs contain:

```
{"level":"fatal","message":"checking if bootstrapped: recovering config: convert field 1 failed: parsing time \"15-JAN-26 13:58:19.626098 +05:30\" as \"2006-01-02 15:04:05.999999999Z07:00\""}
```

**Cause:** The date format returned by the PostgreSQL server does not match the ISO format that the Portal expects. This occurs when the PostgreSQL `DateStyle` is not set to ISO.

**Fix:** Append `datestyle` and `lc_time` options to your `database.connectionString` in `values.yaml`.

For a DSN-format connection string:

```
host=<host> user=<user> password=<pass> dbname=<db> port=5432 sslmode=disable options=-c datestyle=ISO,MDY -c lc_time=C
```

For a URL-format connection string:

```
postgres://<user>:<pass>@<host>:5432/<db>?options=-c%20datestyle%3DISO%2CMDY%20-c%20lc_time%3DC
```

### License Key Not Set

If the Portal is started without a valid Tyk license, it logs the following at startup:

| Log message                              | Meaning                                              |
| ---------------------------------------- | ---------------------------------------------------- |
| `Initializing license: license is empty` | `license` field is missing or empty in `values.yaml` |
| `Initializing license: token not valid`  | License key is set but malformed or expired          |
| `Licensing: license is invalid`          | Periodic background check; license failed validation |

**Fix:** Set the `license` field in your `values.yaml`. If using a Kubernetes secret, confirm the secret contains a `DevPortalLicense` key and that `useSecretName` references it:

```bash theme={null}
kubectl get secret <secret-name> -n <namespace> -o jsonpath='{.data.DevPortalLicense}' | base64 -d
```

### Environment Variables Not Taking Effect

**Symptom:** Configuration set via `extraEnvs` (such as `PORTAL_STORAGE` or `PORTAL_DATABASE_DIALECT`) is not reflected at runtime. The Portal continues using previous values.

**Cause:** The Helm chart generates environment variables for certain fields (including storage type and database dialect) from its own templated values. Variables passed through `extraEnvs` may be overridden by these chart-generated values.

**Fix:** Use the chart's native fields in `values.yaml` instead of `extraEnvs` for these settings:

| Instead of `extraEnvs`             | Use directly in `values.yaml` |
| ---------------------------------- | ----------------------------- |
| `PORTAL_STORAGE=db`                | `storage.type: db`            |
| `PORTAL_DATABASE_DIALECT=postgres` | `database.dialect: postgres`  |

Reserve `extraEnvs` for configuration options that have no direct Helm chart equivalent.
