ntoledo319

Every deprecated-runtime migration produces the same shape of pain: you bump one version number, redeploy, and get hit with errors that look unrelated to each other but are all downstream of the same jump. The errors aren't random — for a given upgrade path, they show up in a fairly predictable order.

This is a map, not a new deep dive. Each line below is a real, verbatim error with its own fix already written up — this just sequences them by which upgrade produces them, so you know what's coming before you hit it instead of debugging one surprise at a time.

Path 1: Python 3.9 (or earlier) → Python 3.12 on Lambda

You're doing this because AWS blocks python3.9 creates/updates Feb 1 / Mar 3 2027 (and earlier versions are already blocked). Python 3.12 removed a batch of stdlib modules in one release (PEP 632/594), so this path front-loads the most breakage:

  1. ModuleNotFoundError: No module named 'distutils' — removed in 3.12. Fix →
  2. ModuleNotFoundError: No module named 'imp' — removed in 3.12. Fix →
  3. AttributeError: module 'collections' has no attribute 'Mapping' — moved to collections.abc (removed from collections in 3.10, so this can also hit on the way to 3.10/3.11). Fix →
  4. ModuleNotFoundError: No module named 'smtpd' — removed in 3.12. Fix →
  5. ModuleNotFoundError: No module named 'asyncore' — removed in 3.12, usually alongside smtpd. Fix →
  6. DeprecationWarning: datetime.datetime.utcnow() is deprecated — not fatal, but noisy, and worth fixing in the same pass. Fix →
  7. /lib64/libc.so.6: version 'GLIBC_2.28' not found — if you ship any native dependency (cryptography, numpy, psycopg2, pydantic-core), moving to the AL2023-based Python 3.12 runtime (glibc 2.34) from an AL2-based one (glibc 2.26) can surface this separately from the stdlib removals above. Fix →

Path 2: Python 3.11/3.12 → Python 3.13

A second, smaller PEP 594 wave hits on the next hop:

  1. ModuleNotFoundError: No module named 'cgi' — removed in 3.13. Fix →
  2. ModuleNotFoundError: No module named 'telnetlib' — removed in 3.13. Fix →
  3. ModuleNotFoundError: No module named 'crypt' — removed in 3.13. Fix →
  4. ModuleNotFoundError: No module named 'lib2to3' — removed in 3.13. Fix →

And one that hits on the way into 3.11, if you skipped straight past it:

  • AttributeError: module 'asyncio' has no attribute 'coroutine' — the legacy @asyncio.coroutine decorator, removed in 3.11. Fix →

Path 3: Node.js 16/18 → Node.js 20/22 on Lambda

This path is less about stdlib removals and more about what the runtime stopped bundling and what OpenSSL 3 stopped allowing:

  1. Error: Cannot find module 'aws-sdk' — AWS SDK v2 stopped shipping preinstalled from nodejs18.x onward; only @aws-sdk/* v3 is preinstalled now. This is usually the first error you hit, at cold start. Fix →
  2. Error: error:0308010C:digital envelope routines::unsupported — OpenSSL 3 (bundled from Node 17+) rejecting a legacy hash, often from an older build tool (webpack 4). Fix →
  3. error:1E08010C:DECODER routines::unsupported — OpenSSL 3 refusing to load a private key stored in a legacy format (PKCS#1, or encrypted with a weak cipher). Fix →
  4. Error: The module was compiled against a different Node.js version using NODE_MODULE_VERSION — any native addon (sharp, bcrypt, better-sqlite3) needs a rebuild for the new ABI. Fix →
  5. Node Sass does not yet support your current environment — node-sass specifically, since LibSass is dead and ships no Node 22 prebuild. Fix →
  6. TypeError: crypto.createCipher is not a functioncreateCipher/createDecipher were removed outright in Node 22 (not just deprecated). Fix →
  7. [DEP0040] DeprecationWarning: The 'punycode' module is deprecated — not fatal, usually from a transitive dependency, loudest on Node 22. Fix →

If none of the above matches and you're just staring at a bare Runtime.ImportModuleError: Cannot find module, the cause could be any of #1 or #4 above, an esbuild 0.22+ bundling default change, or a Lambda layer built on the wrong OS/arch — see the dedicated triage guide to tell them apart before guessing.

Path 4: Amazon Linux 2 → Amazon Linux 2023

AL2 reaches end of life June 30, 2026. This path isn't a Lambda runtime change at all — it's the base OS on EC2/ECS/EKS nodes — but it produces the same "one version bump, five unrelated-looking failures" shape:

  1. amazon-linux-extras: command not found — the Extras Library mechanism doesn't exist on AL2023 at all. Fix →
  2. Error: Unable to find a match: <package> — package renamed, version-namespaced, moved to SPAL, or dropped. Fix →
  3. Failed to start ntpd.service: Unit ntpd.service not found — AL2023 uses chronyd. Fix →
  4. Failed to start iptables.service: Unit iptables.service not found — AL2023 defaults to nftables. Fix →
  5. /usr/bin/env: 'python2': No such file or directory — AL2023 ships no Python 2 at all. Fix →

Why this exists as one page

Each fix above already has its own full write-up — root cause, verified fix steps, primary source. What's usually missing when you're mid-migration isn't any single fix, it's knowing what's coming next so you can batch the work instead of playing whack-a-mole one redeploy at a time. Bookmark whichever path applies to you and work down it in order.

If you'd rather have this run against your actual account instead of reading it, the free EOLkits scanner checks in about 30 seconds, nothing uploaded — I maintain it, disclosing that plainly since it's the one link in this piece that isn't a fix.