PostStartHookError occurs when a container lifecycle postStart hook fails. The hook failure kills the container, causing restart loops. Fix the hook command or remove it.
Fixes FailedPostStartHook
kubectl describe pod <pod-name>kubectl describe pod <pod-name>FailedPostStartHook
PostStartHookError (FailedPostStartHook) occurs when a container's postStart lifecycle hook fails to execute successfully. PostStart hooks run immediately after a container is created, and any failure causes Kubernetes to kill the container. This creates a challenging situation: the container starts, the hook runs and fails, the container is killed, and the cycle repeats. The pod may appear stuck in ContainerCreating or enter a restart loop depending on timing.
Inspect pod events:
kubectl describe pod <pod-name>Look for:
- FailedPostStartHook events
- Specific error messages (may be empty in newer K8s versions)
Also check:
kubectl get events --field-selector involvedObject.name=<pod-name>Remove the hook temporarily and test in the running container:
# Comment out the lifecycle hook
# lifecycle:
# postStart:
# exec:
# command: ["/scripts/init.sh"]Then exec in and test:
kubectl exec -it <pod-name> -- /bin/sh
/scripts/init.sh
echo $? # Check exit codeCommon issues:
# Wrong - command doesn't exist
lifecycle:
postStart:
exec:
command: ["/nonexistent/script.sh"]
# Wrong - no execute permission
lifecycle:
postStart:
exec:
command: ["/scripts/init.sh"] # Missing chmod +x
# Correct
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "chmod +x /scripts/init.sh && /scripts/init.sh"]PostStart hooks don't automatically log to kubectl logs. Redirect output:
lifecycle:
postStart:
exec:
command:
- /bin/sh
- -c
- |
/scripts/init.sh > /proc/1/fd/1 2>&1This sends hook output to the container's stdout where kubectl logs can capture it.
If the hook connects to services not yet ready:
lifecycle:
postStart:
exec:
command:
- /bin/sh
- -c
- |
sleep 5 # Wait for container to stabilize
curl -f http://localhost:8080/ready || exit 0 # Don't fail if not readyConsider whether the logic belongs in the application startup instead of a hook.
For calling endpoints, HTTP hooks can be cleaner:
lifecycle:
postStart:
httpGet:
path: /initialize
port: 8080
scheme: HTTPNote: HTTP GET hooks also fail if the endpoint returns non-2xx status, so ensure your endpoint is ready immediately on container start.
PostStart hooks have tricky semantics:
- They run asynchronously relative to container start, but must complete
- Hook failure kills the container
- There's no timeout—hooks can run indefinitely (blocking other operations)
- Kubernetes doesn't guarantee the hook completes before ENTRYPOINT
For complex initialization logic, consider:
1. Init containers (run before main container)
2. Application-level startup logic
3. Sidecar containers for ongoing tasks
PostStart is best for simple, fast, non-critical tasks. Critical initialization should use init containers which have better error handling and retry semantics.
In Kubernetes 1.25+, FailedPostStartHook events may have empty messages due to API changes. Check kubelet logs on the node for detailed errors.