DiyMediaServer
Featured image of post How to Upgrade Debian 12 to 13 in Proxmox LXC Without CREDENTIALS Errors (2026)

How to Upgrade Debian 12 to 13 in Proxmox LXC Without CREDENTIALS Errors (2026)

Fix the 243/CREDENTIALS errors that break a Debian 12 to 13 upgrade in an unprivileged Proxmox LXC, using Debian's lxc.generator.

Are you running Debian 12 (Bookworm) in an LXC container on Proxmox and want to upgrade to 13 (Trixie)? Should be straightforward, right? Well, if you’ve landed here, you’ve probably discovered that systemd has other plans.

Here’s the thing. systemd 256+ introduces stricter credential handling that doesn’t play nicely with unprivileged LXC containers. Try the upgrade and you’ll hit the dreaded 243/CREDENTIALS error that stops things dead.

Here’s how to work around it and upgrade your Debian LXC to Trixie without pulling your hair out.

💭
TL;DR: Debian 13’s systemd 257 enables credential plumbing by default, which breaks unprivileged LXC containers with cryptic 243/CREDENTIALS errors. Install Debian’s lxc.generator before you upgrade, reload systemd, then upgrade to Trixie. Leave the generator in place afterwards. Removing it hands the same failures straight back on the next reboot.

I’m writing this inside one of those containers. It’s an unprivileged LXC on Proxmox VE 9.2.5 (kernel 7.0.14-6-pve) running Debian 13.6 with systemd 257.13-1~deb13u1. I dropped the generator into it on 14 September 2025 and never took it back out. As I type this, systemctl is-system-running returns running with zero failed units and userspace boots in 492 ms.

Upgrading Debian containers inside Proxmox VE should be boring. Boring is why you run Debian. Change your apt sources, run the upgrade, reboot, get on with your life. That’s what the Reddit threads kept telling me when Debian 13 “Trixie” dropped. But if you’re running unprivileged and unnested LXCs on Proxmox 9, you already know that’s not how it goes. The result? A blinking cursor, status=243/CREDENTIALS failures, and crawling through logs that don’t want to work.

So we’ll take it in order. Why the error happens. What breaks when you ignore it. How to get back into a container you’ve already broken. And why a fresh Debian 13 container that was never upgraded at all greets you with the exact same mess.

MINISFORUM MS-A2
MINISFORUM MS-A2 Up to a 16-core Ryzen 9 9955HX in something you can hide behind a monitor, with dual 10GbE SFP+ and dual 2.5GbE on board. The core count is what matters for this kind of work: enough headroom to run a stack of LXCs and still have something left over when one of them decides to rebuild its package cache mid-upgrade. Storage takes U.2 and full-length M.2 22110, so you’re not limited to whatever fits a laptop slot.
Amazon Price: Loading...
Availability: Checking...
Contains affiliate links. I may earn a commission at no cost to you.

Why Upgrading Debian 12 to 13 Breaks on Proxmox 9

When you upgrade Debian 12 to 13 (Bookworm to Trixie), the culprit hiding in the shadows is systemd 256+. Debian 13 ships systemd 257. That release enabled unit credentials (LoadCredential and ImportCredential) by default, which sounds harmless enough.

On bare metal or regular VMs, it works fine. But inside Proxmox LXCs, especially unprivileged ones, this feature crashes headfirst into the container’s limited namespace access. Here’s the breakdown:

  • systemd-sysctl (the service that applies kernel parameters) tries to load credentials
  • LXC blocks the namespace operation because the container doesn’t have permission
  • systemd throws a status=243/CREDENTIALS error and gives up
  • Other core services cascade into failure, from udev triggers to login shells

Most likely upgrade error:

Job for systemd-sysctl.service failed because the control process exited with error code.
See "systemctl status systemd-sysctl.service" and "journalctl -xeu systemd-sysctl.service" for details.
Processing trigger

systemctl status systemd-sysctl.service:

x systemd-sysctl.service - Apply Kernel Variables
     Loaded: loaded (/usr/lib/systemd/system/systemd-sysctl.service; static)
     Active: failed (Result: exit-code) since Sun 2025-09-14 05:59:21 MDT; 48s ago
   Duration: 2h 59min 12.451s
 Invocation: 63213f2f7514402f8cedd10155c7d065
       Docs: man:systemd-sysctl.service(8)
             man:sysctl.d(5)
    Process: 17806 ExecStart=/usr/lib/systemd/systemd-sysctl (code=exited, status=243/CREDENTIALS)
   Main PID: 17806 (code=exited, status=243/CREDENTIALS)
   Mem peak: 1.7M
        CPU: 5ms

What that error means

systemd is trying to pass secrets inside a container that has no infrastructure for handling them. Your services never start. The container hangs during boot. And debugging is a mess, because half the logging system went down with everything else.

243/CREDENTIALS = “failed to set up the unit’s credentials”.

Nesting, and what Proxmox actually recommends

The other way out of this is nesting. I want to be honest with you about it, because the original version of this post was harder on nesting than the facts support.

Proxmox’s own position is that modern systemd needs it. Their staff have said so plainly on the forums: systemd versions 242 and newer want nesting so they can create the Linux namespaces used to isolate services. That requirement has since been written into the pve-container package itself, where the nesting feature description now ends with the line “That is also required by systemd to isolate services.” Enabling it is one command on the host:

pct set <CTID> --features nesting=1
pct reboot <CTID>

That same requirement is where the WARN: systemd 257 detected. You may need to enable nesting. line in your task log comes from. It’s a version check on the container’s systemd and it never inspects whether anything is broken, so it fires in identical words on a guest that booted perfectly and on a guest whose console is a black rectangle. It also keeps firing after you fix the container by any route other than the flag, which is why you confirm a repair with systemctl is-system-running inside the container instead of trusting the absence of a warning. I stripped the flag off eight containers to measure what it switches, what it exposes, and what actually breaks without it, and that lives in its own post: Systemd 257 detected: enable nesting in Proxmox LXC?

The security tradeoff is real, but it’s narrower than it sounds. On an unprivileged container, nesting exposes the host’s procfs and sysfs contents to the guest. The Proxmox documentation describes the feature as “best used with unprivileged containers with additional id mapping,” which is another way of saying it’s the supported configuration rather than a workaround. Privileged plus nesting is the combination that should worry you. Proxmox staff describe that pairing as “essentially uncontained.”

For the record, every container in my own fleet now runs unprivileged with nesting=1. The generator approach in this post is what you reach for when you specifically want nesting turned off, or when you’re upgrading a container in place and would rather not change its feature flags mid-migration. Both paths work. Pick the one whose tradeoff you’d rather own.

What breaks if you don’t fix it

Try to upgrade to Debian 13 (Trixie) without handling the systemd changes first, and your LXC container becomes a flashing cursor:

  • The container won’t boot cleanly. It hangs there, mocking your weekend plans.
  • Critical systemd units like systemd-sysctl, systemd-udev-trigger, systemd-udev-load-credentials and terminal login will fail consistently. One report against the community-scripts project counted 19 failed units on a fresh Debian 13 container that had never been upgraded at all.
  • journald may crash, which means you lose the diagnostic logs you desperately need to figure out what went wrong.
  • The Proxmox noVNC console shows nothing at all, because agetty is one of the casualties.

That last point catches people out, and it’s also the thing that saves you. The console being dead doesn’t mean the container is unreachable. See the recovery section below.

ASRock Mini-Desktop Computer
ASRock Mini-Desktop Computer A 1.92L barebone that takes any 65W LGA1700 chip from 12th through 14th Gen, so you pick the CPU rather than accepting whatever a vendor soldered down. Two SO-DIMM slots reach 64GB, and you get a Gen5 x4 M.2, a Gen4 x4 M.2 and two 2.5-inch bays. It’s a barebone, so budget for the CPU, RAM, cooler and drives on top of the sticker price.
Amazon Price: Loading...
Availability: Checking...
Contains affiliate links. I may earn a commission at no cost to you.

The Fix: lxc.generator for Proxmox LXC Templates

Debian includes a small but clever utility called lxc.generator (part of the distrobuilder package) that solves this problem. It runs early in the systemd boot sequence and automatically patches unit files to make them container-friendly Debian Sources. Here’s what it does:

  • Detects when the system is running inside an LXC container or an unprivileged environment
  • Strips problematic flags like LoadCredential= and ImportCredential= that cause the 243/CREDENTIALS errors
  • Relaxes security hardening settings that don’t work properly in containers
  • Masks services that would otherwise crash during container startup

The generator creates temporary drop-in files under /run/systemd/ rather than permanently modifying anything on disk. Nothing on your root filesystem changes, and the drop-ins are rebuilt from scratch on every boot.

⚠️
Warning: Tested on Proxmox VE 9.x with unprivileged Debian LXCs. It should also help in LXD or Incus, but I have not tested there.

What the generator actually changes

The original version of this post claimed the generator kept your security posture intact with no compromises. That wasn’t quite right, and anyone who read the script would have caught me out. Here’s the drop-in it writes to /run/systemd/system/service.d/zzz-lxc-service.conf on a Debian 13 container, copied from the container this post was written in:

[Service]
ProcSubset=all
ProtectProc=default
ProtectControlGroups=no
ProtectKernelTunables=no
NoNewPrivileges=no
LoadCredential=
PrivateNetwork=no
ImportCredential=

That’s a global drop-in. It applies to every service in the container, and it turns off a meaningful chunk of systemd’s per-service sandboxing to do it. NoNewPrivileges=no in particular is not nothing.

So the honest framing is that both options cost you something. Nesting widens what the guest can see of the host. The generator widens what services inside the guest can do to each other. Neither is free, and which one you prefer depends on which boundary you actually care about.

It also writes a per-unit override for the service that started this whole mess:

# This file was created by distrobuilder
[Service]
ExecStart=
ExecStart=-/usr/lib/systemd/systemd-sysctl

The leading - tells systemd to tolerate a non-zero exit from systemd-sysctl instead of failing the unit, which is why the container stops cascading into failure.

1) Patch each Debian 12 container before upgrading

Before you upgrade Debian 12 to 13, install a small fix that prevents systemd from breaking during the transition. Enter your Debian 12 (Bookworm) LXC container and run:

sudo mkdir -p /etc/systemd/system-generators
curl -fsSL https://sources.debian.org/data/main/d/distrobuilder/3.2-2/distrobuilder/lxc.generator \
  | sudo tee /etc/systemd/system-generators/lxc >/dev/null
sudo chmod 0755 /etc/systemd/system-generators/lxc
sudo systemctl daemon-reload
💡
Tip: The generator tells systemd to disable the credential features that cause the 243/CREDENTIALS error. Install it while the container is still healthy, so the fix is already in place when the new systemd arrives.

Now prove it took effect before you go any further. A daemon-reload runs the generator, so the drop-in should exist immediately:

cat /run/systemd/system/service.d/zzz-lxc-service.conf

If that file is missing, the generator didn’t run. Check that it’s executable (ls -l /etc/systemd/system-generators/lxc should show 0755) and that the download wasn’t truncated (it’s roughly 7 KB). Fix that before upgrading, because this is the last comfortable moment to do it.

2) Upgrade to Debian 13 (Trixie)

Still inside your LXC container:

# Make sure Bookworm is up to date
sudo apt update && sudo apt upgrade -y

# Update every sources file to Trixie, old-style and deb822 alike
for f in /etc/apt/sources.list \
         /etc/apt/sources.list.d/*.list \
         /etc/apt/sources.list.d/*.sources; do
  [ -f "$f" ] && sudo sed -i 's/bookworm/trixie/g' "$f"
done
sudo apt update

# Upgrade across versions
sudo apt dist-upgrade -y

# Clean up junk
sudo apt autoremove -y
sudo apt autoclean -y

# Modernize apt format (optional but recommended)
sudo apt modernize-sources || true

# Reload systemd configs and reboot
sudo systemctl daemon-reload
sudo reboot
⚠️
Warning: Earlier versions of this post rewrote only /etc/apt/sources.list. That misses two common cases: repositories dropped into /etc/apt/sources.list.d/, and containers that already run the deb822 .sources format, where /etc/apt/sources.list may not exist at all. The loop above covers all three paths. Run apt update and read the output before you commit to dist-upgrade.

3) Verify

The upgrade takes a few minutes, depending on how big the container is and how fast your mirror is. When it comes back, check three things:

cat /etc/os-release
systemctl is-system-running
systemctl --failed

You should see something like:

PRETTY_NAME="Debian GNU/Linux 13 (trixie)"
VERSION_ID="13"
VERSION="13 (trixie)"
VERSION_CODENAME=trixie
DEBIAN_VERSION_FULL=13.6

See “trixie” in the output? Good. Now check the second and third commands: is-system-running should print running, and systemctl --failed should list nothing. A degraded result with 243/CREDENTIALS units in the list means the generator isn’t doing its job, so go back and check the drop-in from step 1.

Debian 13.6 has been the current point release since 11 July 2026. Yours will differ depending on when you read this, and a higher DEBIAN_VERSION_FULL is nothing to worry about.

4) Leave the generator in place

This is the one instruction I’ve reversed since first publishing this post, and it’s worth explaining why.

The original advice was to delete /etc/systemd/system-generators/lxc once the upgrade completed, on the theory that it was a temporary bridge. It isn’t. The credential behaviour that broke your container during the upgrade is the ordinary behaviour of systemd 257 on Debian 13, so removing the generator hands you the same failures back on the next reboot. That’s borne out by everyone who creates a fresh Debian 13 container with nesting off and watches it come up degraded without ever having run an upgrade at all.

The container I’m writing this in has had the generator installed since 14 September 2025. It’s been through the 13.1 through 13.6 point releases and every reboot along the way, the most recent on 24 July 2026, and it still reports zero failed units. Leave it alone.

If you do want it gone, enable nesting first and reboot, then confirm the container still reports running before you delete anything.

Already upgraded and now the container won’t boot

If you found this post after running the upgrade, you’re not stuck, and you almost certainly don’t need to restore from backup.

The critical detail: the Proxmox console dying doesn’t mean the container is unreachable. agetty fails on credentials, which kills the noVNC console, but pct enter attaches through a different path and keeps working. From the Proxmox host:

pct enter <CTID>

Once you’re in, install the generator exactly as in step 1, then reload and reboot:

mkdir -p /etc/systemd/system-generators
curl -fsSL https://sources.debian.org/data/main/d/distrobuilder/3.2-2/distrobuilder/lxc.generator \
  > /etc/systemd/system-generators/lxc
chmod 0755 /etc/systemd/system-generators/lxc
systemctl daemon-reload
cat /run/systemd/system/service.d/zzz-lxc-service.conf   # proof it ran
exit
# back on the host
pct reboot <CTID>

The container should come back with a working console. If pct enter also fails, or networking never came up so you can’t reach sources.debian.org, enable nesting from the host as the fast way back to a shell:

pct set <CTID> --features nesting=1
pct reboot <CTID>

That gets you a bootable container immediately. You can decide afterwards whether to install the generator and turn nesting back off, or leave it on and call it done.

Intel® Core™ i5-14500 14th Generation Desktop Processor
Intel® Core™ i5-14500 14th Generation Desktop Processor 14 cores (6 performance plus 8 efficiency) and 20 threads turboing to 5.0 GHz, with UHD 770 graphics carrying the Quick Sync engine. That last part is why this chip keeps turning up in homelab builds: Jellyfin and Plex get hardware transcoding without a discrete GPU taking up a slot. The thread count suits a Proxmox host running a dozen containers that spend most of their lives idle.
Amazon Price: Loading...
Availability: Checking...
Contains affiliate links. I may earn a commission at no cost to you.

Starting fresh: creating a Debian 13 LXC from a template

Plenty of people arrive here not because an upgrade broke, but because they tried to create a new Debian 13 container and hit a wall. The credential problem is identical. The path to it is different.

Grab the template from the host:

pveam update
pveam available --section system | grep debian-13
pveam download local <template-filename-from-the-list-above>

I’ve deliberately not hardcoded the filename here, because it carries the point release and changes every couple of months. Read it off the pveam available output rather than copying a stale one out of a blog post.

Once the container is created, it runs straight into the same systemd 257 credential behaviour that broke the upgrade path. A fresh Debian 13 container with nesting disabled comes up degraded, and the fix is the same generator install from step 1. This surprises people who assume the problem was caused by the upgrade process. It wasn’t. The upgrade was only when they first met it.

“unsupported debian version” when creating the container

There’s a second, unrelated error that hits Debian 13 containers, and it looks like this:

TASK ERROR: unable to create CT 200 - unsupported debian version '13.1'

Some tooling surfaces it as a complaint that pct reported an unsupported version and the LXC stack might be too old for the template. Same root cause either way: /usr/share/perl5/PVE/LXC/Setup/Debian.pm on the host carries a hardcoded upper bound on the Debian version it will accept, and a template newer than that bound gets rejected before the container is ever created.

The fix is to update Proxmox. Thomas Lamprecht confirmed the version check was reworked in pve-container 6.0.10 for Proxmox VE 9 and 5.3.1 for Proxmox VE 8, both on the pve-no-subscription repository. The refactor also stops the same thing recurring with each new point release, which is what made 13.0 work and 13.1 fail.

apt update && apt install pve-container

If you genuinely can’t update the host right now, the interim workaround is to edit line 39 of /usr/share/perl5/PVE/LXC/Setup/Debian.pm:

# before
die "unsupported debian version '$version'\n" if !($version >= 4 && $version <= 13);

# after
die "unsupported debian version '$version'\n" if !($version >= 4 && $version <= 14);

Restart the host afterwards. Treat this as a stopgap. A package update will overwrite the file, which is fine, because by then you won’t need the edit.

Alternative Options: Pick Your Poison

OptionWhat it costs youEffortUse when…
Enable nesting (unprivileged)Host procfs and sysfs contents visible to the guestLowYou want the configuration Proxmox documents and supports
Use lxc.generator (this post)systemd’s per-service sandboxing relaxed container-wideLowYou want nesting to stay off, or you’re upgrading in place
Flip to privileged LXCUID mapping isolation gone, much larger blast radiusMediumYou need kernel options that won’t work unprivileged
Migrate to VMReal overhead and resource costHighYou want zero container weirdness

The top two are both defensible and I run the first one across my fleet. Avoid combining privileged with nesting, which Proxmox staff describe as essentially uncontained.

FAQs

➤ What does `status=243/CREDENTIALS` mean, exactly?
It’s a systemd error code that translates to “failed to set up credentials.” Starting with systemd 256, the system expects to mount sensitive files like API tokens into service units through tmpfs-backed namespaces. The problem? Unprivileged LXC containers don’t have the kernel options to support this feature, so services that rely on it fail to start.
➤ Why does Proxmox tell me to enable nesting if this post shows a way around it?
Because nesting is the configuration Proxmox supports for modern systemd, and their warning reflects that. The generator is a legitimate alternative when you want nesting off, but it isn’t the officially blessed path. Both work. The generator trades systemd’s in-container sandboxing for the host visibility that nesting would give away.
➤ Could I enable nesting and forget about it?
Yes, and that’s what I do on my own fleet. Nesting exposes more of the host’s /proc and /sys to the container, which is a real cost, but on an unprivileged container with id mapping it’s the arrangement Proxmox recommends. Keep it away from privileged containers, where the combination removes most of the isolation.
➤ Is `lxc.generator` safe to leave on long-term?
Yes, and you should. It only creates ephemeral drop-in files under /run/systemd/, rebuilt on every boot. Removing it hands back the same 243/CREDENTIALS failures on the next reboot, because Debian 13’s credential behaviour doesn’t go away after the upgrade. Mine has run continuously since September 2025.
➤ My container won't boot and the console is black. Have I lost it?
Almost certainly not. The dead console is agetty failing on credentials, not the container being down. Run pct enter <CTID> from the Proxmox host, which uses a different path and usually still works, then install the generator and reboot. Failing that, enable nesting from the host to get a shell back.
➤ Can I use this on LXD instead of Proxmox?
In theory, yes. The lxc.generator is designed to work with LXC containers, not only Proxmox. But I’ve only run these steps on Proxmox VE 9 with unprivileged containers. On LXD or Incus the concepts should carry over fine, and you’d be the one testing that.
➤ Do I need to replace my `sources.list` with deb822 format?
Not required. Your existing old-style sources keep working fine. Debian is nudging everyone toward the newer deb822 format though, and apt modernize-sources handles the conversion for you if you decide you want it. There’s no hurry either way.

Conclusion

Upgrading an unprivileged Debian container on Proxmox shouldn’t require a vocabulary lesson in creative profanity. The culprit is systemd’s credential defaults in 256 and later, which Debian 13 inherits at version 257.

You’ve got two honest ways through it. Enable nesting, which is what Proxmox documents and what I run across my own containers. Or install lxc.generator, keep nesting off, and accept that systemd’s per-service hardening gets relaxed inside the container instead. Install it, reload, upgrade, reboot, and then leave it in place. That last part is the correction I most wanted to make to this post: the generator is not scaffolding you remove once the building is up.

If you’re already staring at a container that won’t boot, pct enter is almost always still open to you. And if you’re creating a fresh Debian 13 container rather than upgrading one, expect exactly the same credential failures, plus a possible unsupported debian version error that a pve-container update clears.

LXC template upgrades only look straightforward until systemd changes the rules mid-game. So when a container comes up degraded after some future point release, run ls /run/systemd/system/service.d/ before you go digging through logs. One command tells you whether the generator is still doing its job.

RaspberryPi 4GB
RaspberryPi 4GB Quad-core ARM, 4GB of RAM, Gigabit Ethernet and dual-band Wi-Fi, sipping a few watts. It won’t run your media server and isn’t meant to. Think of it as the machine you keep around for Pi-hole or Home Assistant, and for the throwaway Debian install you can break on purpose to see what a failed upgrade looks like before you try it on something you care about.
Amazon Price: Loading...
Availability: Checking...
Contains affiliate links. I may earn a commission at no cost to you.

Sources