DevOps & Cloud
Build, container, and cloud failures — Docker, Kubernetes, AWS, and CI pipelines that stopped working.
Git: fatal: detected dubious ownership in repository
Since the CVE-2022-24765 fix in Git 2.35.2, Git refuses to read a repository whose working tree or .git directory is owned by a different user than the one running the command. It shows up in containers, CI jobs, sudo sessions and shared drives. Fix the ownership if the repo should be yours, or add the exact path to safe.directory in your global config — never in the repo's own config, which Git ignores for this.
Kubernetes: Internal error occurred: failed calling webhook
An admission webhook sits in front of your write, the API server could not get an answer out of it, and failurePolicy: Fail turned that silence into a rejection. The tail of the message is the whole diagnosis: context deadline exceeded means the call went nowhere, no endpoints available means nothing is running, and an x509 line means the API server does not trust the webhook's certificate. Each has a different fix, and none of them is your manifest.
MySQL: ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
A statement waited the full innodb_lock_wait_timeout for a row lock another transaction is still holding, and gave up. sys.innodb_lock_waits names the blocking session and hands you the KILL statement, and a blocking_query of NULL means the blocker is idle on an open transaction. The detail most retry loops get wrong: by default only the timed-out statement is rolled back, so your transaction is still open and still holds every lock it took earlier.
Redis: MISCONF Redis is configured to save RDB snapshots, but it's currently unable to persist to disk
Reads keep working and every write is rejected, because the last background save failed and stop-writes-on-bgsave-error defaults to yes. The log names the real cause — no space, a dir the redis user can't write, a read-only mount at rename time, or fork failing with Cannot allocate memory. Fix the cause, run one BGSAVE, and writes come back on their own with no restart: rdb_last_bgsave_status flips from err to ok. Setting stop-writes-on-bgsave-error no restores writes instantly but leaves the snapshot broken, so treat it as a deliberate trade, not the fix.
Node.js: FATAL ERROR: Reached heap limit — JavaScript heap out of memory (exit 134)
The V8 heap has its own ceiling, derived from system memory and the Node release, and it is often far below the RAM you have; when a build or server reaches it, V8 aborts with FATAL ERROR: Reached heap limit and exit code 134. Read the real limit with v8.getHeapStatistics().heap_size_limit, then raise it with --max-old-space-size (in MiB) or NODE_OPTIONS for a large workload, size it below the cgroup limit inside containers, and use --heapsnapshot-near-heap-limit to catch a leak in a long-running process. Exit 137 with no FATAL ERROR line is a container kill, not this.
Docker: "exec format error" when the container starts — wrong-platform image, no emulator, or a script with no shebang
The container exits on its first instruction with exec format error — the kernel's ENOEXEC, meaning the file exists but cannot be executed here. In practice that is an image built on one CPU architecture (an Apple-silicon Mac produces linux/arm64) and run on another (an x86_64 server) with no QEMU handler registered in binfmt_misc, or an entrypoint script whose first line is not a shebang. uname -m, docker image inspect and ls /proc/sys/fs/binfmt_misc tell the causes apart; the fix is an explicit docker buildx build --platform (or a manifest list for both), QEMU registration or --platform when you mean to emulate, and a #!/bin/sh line for the script.
curl: (60) SSL certificate problem: unable to get local issuer certificate
curl walked the certificate chain the server sent and reached a certificate whose issuer is not in the CA store it is reading, so it refused the connection with exit code 60. The issuer is missing for one of four reasons: the server sends only its leaf certificate without the intermediate (browsers hide this by fetching it themselves), a TLS-inspecting proxy re-signed the site with a company CA that the container or runner does not trust, curl is reading a different CA bundle than you think (CURL_CA_BUNDLE, SSL_CERT_FILE, a vendored curl), or the ca-certificates package is too old. curl -v shows which store was used and openssl s_client shows what the server sent; fix the side that is missing the link and confirm with -w '%{ssl_verify_result}'.
PostgreSQL: FATAL — no pg_hba.conf entry for host
The client reached the server, but no line in pg_hba.conf matched its connection type, source address, database and user, and PostgreSQL denies anything unmatched. The last words of the message — no encryption or SSL encryption — say which kind of connection was refused. Read the rules the server sees with pg_hba_file_rules, add a host or hostssl line for the client's real address with scram-sha-256, and reload with pg_reload_conf(); the first matching line wins, so order and connection type matter as much as the CIDR.
Kubernetes: container terminated with OOMKilled (exit code 137)
OOMKilled means the Linux kernel sent SIGKILL to your container because it crossed the memory limit of its cgroup — or, when there is no limit, because the whole node ran out and the oom_killer picked it. Last State in kubectl describe shows Reason: OOMKilled and Exit Code: 137. Measure the working set with kubectl top, then set a limit above it, make the JVM or Node heap fit inside the limit, and give the pod requests so the node's OOM killer stops choosing it.
PostgreSQL: FATAL — sorry, too many clients already
PostgreSQL refuses the connection because every slot allowed by max_connections is taken — usually by oversized client pools or sessions parked in an open transaction rather than by real load. pg_stat_activity tells you which it is. Free the idle slots and cap the client side first; raising max_connections works but needs a restart and more shared memory.
Docker Hub: toomanyrequests — You have reached your pull rate limit (429)
Docker Hub answers the manifest request with 429 once the pull budget for your source IP (anonymous) or account (Personal) is spent, and the daemon, kubelet, and BuildKit all relay the same toomanyrequests body. A HEAD request against ratelimitpreview/test shows the limit, what's left, and which address is being counted. Log in where the pull actually happens — the runner, the kubelet via imagePullSecrets — or put a pull-through cache in front of the fleet.
pip: error: externally-managed-environment
On Debian 12, Ubuntu 23.04+, and Homebrew, the interpreter ships an EXTERNALLY-MANAGED marker and pip 23.0+ refuses to install into it outside a virtual environment — sudo and --user included, by design under PEP 668. Nothing is broken: use a venv for project dependencies, pipx for command-line tools, or the distro package for scripts the OS itself runs, and keep --break-system-packages for disposable containers.
nginx: 413 Request Entity Too Large on upload
nginx compares the request's Content-Length against client_max_body_size before it proxies anything, so an upload over the 1 MB default is refused with 413 and the backend never sees the file. nginx -T shows which value is really loaded and which hop refused it. Set the limit in the block that covers the upload path — or the Ingress annotation on Kubernetes — and reload.
Docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock
Every docker command is a request the CLI hands to a background daemon over /var/run/docker.sock, and this error means the request never landed — the daemon is stopped, your user isn't in the docker group, or the CLI is aimed at the wrong context. Read which variant you got, fix that one source, and the socket answers again.
Git: push rejected — Updates were rejected because the remote contains work
Git only accepts a push that continues the remote branch, so this rejection means the remote moved on and your branch isn't its descendant. The reject line tells you which case you're in: (fetch first) means you're just behind, (non-fast-forward) means the histories diverged. Pull the remote work in and push, or force-with-lease if you rewrote history on purpose.
Yarn: install fails with an integrity checksum mismatch
Yarn refuses to install a package because the checksum it computed for the tarball doesn't match the value recorded in yarn.lock — usually a corrupt cache, a registry that repackaged the file, or a hand-edited archive. The fix differs by Yarn line: on Berry, purge and refetch with YARN_CHECKSUM_BEHAVIOR=reset; on Classic, clean the cache and reinstall. Don't delete the lockfile.
Docker Compose: network not found
docker compose up stops with a network not found error — either an external network the file expects was never created, or a dangling reference to a network that was pruned or removed. Confirm what the daemon has with docker network ls and what the project expects with docker compose config, then recreate the network by bringing the project down and up, or create the external network first.
kubectl: x509: certificate signed by unknown authority
kubectl reaches the API server but refuses to trust the TLS certificate it presents, because that certificate doesn't trace back to the CA recorded in your kubeconfig — usually a rebuilt cluster, the wrong context, or a corporate proxy, not a real attack. Confirm the server and CA with kubectl config view --minify, read the certificate the server sends with openssl, then refresh the kubeconfig or embed the correct CA.
AWS CLI: InvalidClientTokenId — the security token in the request is invalid
The AWS CLI refuses a command with "The security token included in the request is invalid" because the credentials it sent aren't a live key AWS recognizes — a deleted key, an expired temporary session, or a stale environment variable outranking your profile. Find which credentials the CLI actually used, fix that source, and the next call goes through.
npm: EACCES permission denied on a global install
A global npm install fails with code EACCES because npm is writing into a prefix directory owned by root, and your user account can't create files there. The fix is not sudo — point npm at a prefix you own (or reinstall Node through a version manager) so global installs never need root again.
GitHub: push rejected — GH001 Large files detected (over 100 MB)
GitHub blocks any file over 100 MiB on the server, so the whole push is rejected with GH001. Deleting the file and committing again doesn't help — the oversized blob is still in history. Fix it by amending if it's only in your latest commit, or by rewriting history with git lfs migrate. The history rewrite is destructive: it changes SHAs and needs a force-push.
Terraform: Error acquiring the state lock
Terraform locks the state before any operation that could write it, and this error means it thinks someone else already holds that lock. The Lock Info block tells a real conflict from a stale one: if a run really is in progress, wait; if a job was killed mid-apply, clear the leftover with terraform force-unlock. Never reach for -lock=false.
Kubernetes: Pod stuck in ImagePullBackOff
The kubelet can't fetch your container image, so the Pod never starts and keeps retrying with a growing back-off. The Events in kubectl describe name the exact reason — wrong name or tag, a private registry with no pull secret, or a rate limit. Fix the reference or the credentials and the next retry succeeds.
nginx: 502 Bad Gateway from an upstream
A 502 means nginx is fine but the upstream behind proxy_pass didn't answer, or answered with something nginx can't use. The error log names the exact failure — connection refused, upstream closed early, or a header too big for the buffer. Fix the backend or the buffer, not nginx.
docker: driver failed programming external connectivity (iptables)
docker run -p fails with "driver failed programming external connectivity" after a firewall reload flushes Docker's iptables chains. We'll confirm the chain is gone, restart the daemon to rebuild it, and stop the reload from wiping it again.
Kubernetes pod stuck in CrashLoopBackOff
CrashLoopBackOff means a container starts, exits, and the kubelet keeps restarting it with a growing delay. We'll read the previous container's logs and its exit code to turn the status into a specific reason, then fix that.
AWS S3 PutObject fails with AccessDenied despite an allow policy
An IAM allow is not enough when a bucket policy, an SCP, an explicit deny, or the object-ownership setting blocks the write. Trace the effective permission with the policy simulator instead of stacking on more allows.
git: fatal: refusing to merge unrelated histories
Two branches share no common commit, so Git refuses to merge them by default. Confirm the histories really belong together, then merge or pull with --allow-unrelated-histories.
npm install fails with ERESOLVE peer dependency conflict
npm 7+ refuses to install when a package's peer dependency cannot be satisfied. Read which peer conflicts, align the versions where you can, and reach for --legacy-peer-deps only when no compatible version exists yet.
Docker: no space left on device
Docker's data directory filled up with old images, stopped containers, build cache, and dangling volumes. See what is using the space with docker system df, prune what you do not need, and check whether the host disk or inodes are the real limit.
Git: you are in 'detached HEAD' state
You checked out a commit, tag, or remote branch directly, so HEAD points at a commit instead of a branch. Commits made here belong to no branch and are easy to lose. Make a branch to keep them, or switch back.
docker: Bind for 0.0.0.0:PORT failed: port is already allocated
Another container — often a stopped one Docker has not removed — already publishes that host port. Find it with docker ps -a, stop or remove it, or publish on a different host port. If nothing shows, a host process owns it.