This error occurs when APT cannot authenticate to a package repository that requires credentials. Common causes include missing subscription credentials for enterprise repositories (like Proxmox), expired authentication tokens, or misconfigured repository URLs with invalid credentials.
The "W: Failed to fetch URL 401 Unauthorized" warning indicates that APT attempted to access a repository that requires authentication, but the provided credentials were invalid, missing, or expired. HTTP 401 Unauthorized is a standard status code meaning the server requires authentication and either: - No authentication credentials were provided in the repository URL - The credentials (username/password or token) are incorrect - The authentication token has expired - The subscription license is no longer valid - Basic authentication is not enabled on the repository This commonly occurs in several scenarios: - **Proxmox Enterprise Repository**: The default Proxmox VE installation includes the enterprise repository URL, which requires a valid subscription. Without a subscription key, all update attempts fail with 401. - **Private Debian/Ubuntu repositories**: Custom repositories hosted on internal servers or cloud services (Gemfury, Artifactory, Nexus) that require authentication tokens or credentials. - **Token-based authentication**: Repositories like GitHub Packages that use OAuth tokens instead of traditional usernames and passwords. - **Expired credentials**: If credentials or tokens were stored but have since expired or been revoked. The error is prefixed with "W:" (warning) rather than "E:" (error), meaning apt continues attempting other repositories but this one fails.
First, identify the exact repository URL that's failing. The error message should show it:
sudo apt updateLook for output like:
W: Failed to fetch https://enterprise.proxmox.com/debian/pve/dists/bookworm/InRelease 401 UnauthorizedWrite down the failing repository URL. In this example, it's https://enterprise.proxmox.com/debian/pve/.
Check your sources list files:
# Check main sources.list
cat /etc/apt/sources.list | grep -v '^#'
# Check additional source lists
ls /etc/apt/sources.list.d/
cat /etc/apt/sources.list.d/*.list 2>/dev/null | grep -v '^#'The failing URL will be in one of these files. This helps you determine which repository needs fixing.
If you're using Proxmox VE without a subscription, the enterprise repository will always fail with 401. You have two options:
Option 1: Use the GUI (Recommended for beginners)
1. Open Proxmox web interface (https://your-proxmox-ip:8006)
2. Navigate to: Datacenter → Nodes → [YOUR-NODE] → Updates → Repositories
3. You'll see several repository entries
4. Find the one with URL https://enterprise.proxmox.com/...
5. Click the row to select it, then click the "Disable" button (or eye icon to hide)
6. Look for "Proxmox VE No-Subscription" repo - enable it if not already enabled
7. Close the dialog and run apt update again
Option 2: Edit configuration files directly
Disable the enterprise repository:
sudo nano /etc/apt/sources.list.d/pve-enterprise.listComment out or delete the line:
# deb https://enterprise.proxmox.com/debian/pve bookworm pve-enterpriseThen add the no-subscription repository to your main sources.list:
sudo nano /etc/apt/sources.listAdd this line:
deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb http://deb.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
# Proxmox VE No-Subscription repository
deb http://download.proxmox.com/debian/pve bookworm pve-no-subscriptionOption 3: If you have a valid subscription
If you actually have a Proxmox VE subscription, verify your subscription key:
1. Open Proxmox web interface
2. Go to Datacenter → Subscription
3. Check if a subscription is active
4. If expired or missing, click "Register Subscription" or "Check" to validate
Once valid, the enterprise repository should authenticate successfully.
After making changes, test:
sudo apt updateFor private repositories that require authentication, use the /etc/apt/auth.conf file instead of embedding credentials in sources.list.
Create or edit the auth file:
sudo nano /etc/apt/auth.confAdd credentials in this format:
machine repo.example.com
login username
password your-passwordOr for token-based authentication (like GitHub):
machine github.com
login oauth2
password ghp_xxxxxxxxxxxxxxxxxxxxFor multiple repositories:
machine repo1.example.com
login user1
password pass1
machine repo2.example.com
login user2
password pass2Set proper permissions (CRITICAL):
sudo chmod 600 /etc/apt/auth.confThe file must be readable only by root. If permissions are wrong, APT will ignore it.
Update your sources.list to remove embedded credentials:
Before:
deb https://username:[email protected]/debian bookworm mainAfter:
deb https://repo.example.com/debian bookworm mainAPT will automatically use credentials from auth.conf when accessing the repository.
Test the configuration:
sudo apt updateIf you must embed credentials directly in sources.list, special characters in passwords must be URL-encoded.
Special characters that need encoding:
| Character | URL Encoding |
|-----------|--------------|
| @ | %40 |
| : | %3A |
| / | %2F |
| # | %23 |
| ? | %3F |
| & | %26 |
| = | %3D |
| % | %25 |
Example with encoded password:
If your password is pass@word#123, encode it as pass%40word%23123
Wrong (will fail with 401):
deb https://user:pass@word#[email protected]/debian bookworm mainCorrect:
deb https://user:pass%40word%[email protected]/debian bookworm mainTo URL-encode a password in bash:
python3 -c "import urllib.parse; print(urllib.parse.quote('pass@word#123', safe=''))"However, using /etc/apt/auth.conf is strongly recommended over embedding credentials in source URLs.
For repositories using token-based authentication (GitHub Packages, GitLab, etc.), verify the token hasn't expired:
For GitHub Packages:
# Token should be a Personal Access Token (classic or fine-grained)
# Check token expiration at: https://github.com/settings/tokens
# Example sources.list entry:
# deb https://username:[email protected]/owner/repo-name/debian bookworm mainFor GitLab Package Registry:
# Token should be a Personal Access Token or Deploy Token
# Check token expiration at: https://gitlab.example.com/-/profile/personal_access_tokens
# Example:
# deb https://gitlab-ci-token:[email protected]/api/v4/projects/1234/packages/deb bookworm mainCheck if token is expired:
1. Go to your token management page in the service (GitHub, GitLab, etc.)
2. Look for "Expiration" or "Expires at" field
3. If expired, generate a new token
4. Update your sources.list or auth.conf with the new token
5. Run sudo apt update to test
For services with token expiration:
# Regenerate token regularly in automation
# Or use tokens without expiration if availableTypos or outdated repository URLs will cause authentication failures:
Check if the repository is still active:
# Test the repository with curl
curl -v https://repo.example.com/debian/Release
# If you get 401, test with credentials
curl -u username:password https://repo.example.com/debian/ReleaseCommon repository URL changes:
Some repositories move or change their URLs. Check if your sources.list has old URLs:
Outdated URLs:
- deb https://archive.ubuntu.com/ubuntu → deb http://archive.ubuntu.com/ubuntu
- deb https://ppa.launchpad.net/some-old-ppa → May have been removed entirely
- deb https://deb.example.com → May have moved to deb https://packages.example.com
To verify a repository is still active:
# Check the Releases file without authentication
curl -i https://repo.example.com/debian/dists/bookworm/Release
# 401 means you need credentials
# 404 means the repository no longer exists
# 200 means it's accessibleUpdate sources.list if needed:
sudo nano /etc/apt/sources.list.d/myrepo.list
# Update the URL to the correct one
# deb https://old-repo.example.com/debian bookworm main
# deb https://new-repo.example.com/debian bookworm mainThen test:
sudo apt updateAPT won't use auth.conf if permissions are wrong, or if using an older APT version that doesn't support it.
Verify auth.conf has correct permissions:
ls -l /etc/apt/auth.confOutput should look like:
-rw------- 1 root root 1024 Jan 1 10:00 /etc/apt/auth.confIf it shows -rw-r--r-- (world-readable), APT ignores it. Fix with:
sudo chmod 600 /etc/apt/auth.confCheck if your APT version supports auth.conf:
apt --versionauth.conf support was added in APT 0.7.25 (released in 2008), so virtually all modern systems have it. If you're on an extremely old system, consider updating.
Verify APT is reading auth.conf:
Enable APT debugging:
sudo apt update -o Debug::Acquire::http=true 2>&1 | grep -i authYou should see APT attempting to use the credentials from auth.conf.
If auth.conf is still not working:
Try embedding credentials directly (less secure but works for testing):
# Edit sources.list temporarily
sudo nano /etc/apt/sources.list.d/test.list
# Add: deb https://username:[email protected]/debian bookworm main
# (use URL-encoded password if it has special characters)
sudo apt updateIf this works, the issue is with auth.conf. If this also fails, the problem is with the credentials themselves.
Sometimes 401 errors mask network connectivity issues. Verify you can reach the repository:
Test basic connectivity:
# Ping the repository host
ping -c 3 repo.example.com
# Or use ping with DNS:
nslookup repo.example.comTest HTTPS connectivity:
# Check if HTTPS port is open
curl -v https://repo.example.com/debian/Release 2>&1 | head -20
# This should show either:
# - SSL/TLS handshake details
# - 401 Unauthorized (good - you can reach it)
# - Connection timeout (network issue)
# - Connection refused (host or firewall blocking)If behind a corporate proxy:
Configure APT to use the proxy:
sudo nano /etc/apt/apt.conf.d/proxy.confAdd:
Acquire::http::Proxy "http://proxy.example.com:8080";
Acquire::https::Proxy "http://proxy.example.com:8080";Or with credentials:
Acquire::http::Proxy "http://username:[email protected]:8080";Check firewall rules:
# On the APT client machine, check if 443 is open to the repository
sudo iptables -L -n | grep HTTPS
# Or use nc (netcat) to test connectivity
nc -zv repo.example.com 443If the server is unreachable, you'll see "Connection refused" or "timed out" rather than 401.
Understanding HTTP 401 vs other failures:
When apt shows "401 Unauthorized", it means the server received the request and explicitly rejected it due to missing/invalid credentials. This is different from:
- 403 Forbidden: Authentication succeeded, but user lacks permission (credentials valid but insufficient)
- 404 Not Found: Repository URL is wrong or no longer exists
- Connection refused: Network or firewall issue, server not reachable
- SSL errors: TLS/certificate issues, not authentication
APT authentication mechanism details:
APT supports two authentication methods:
1. HTTP Basic Auth: Username and password in URL or auth.conf
- Requires HTTPS for security
- Supported since APT 0.7.25 (2008)
- Uses Authorization header with Base64-encoded credentials
2. Netrc-style configuration: auth.conf file
- More secure (credentials not in source list files)
- Applied per-host from auth.conf
- APT reads this automatically if permissions are correct
Why Proxmox shows 401 specifically:
Proxmox enterprise repositories use API key authentication. When you subscribe:
1. You receive a subscription key
2. During Proxmox setup, this key is registered in the web interface
3. Proxmox adds a proxy certificate to your system
4. APT uses this certificate to authenticate to enterprise.proxmox.com
Without a subscription key:
- No certificate is provisioned
- Repository requests are unauthenticated
- Proxmox returns 401
- APT shows "Failed to fetch 401 Unauthorized"
Private repository patterns:
Different hosting services use different authentication methods:
| Service | Pattern | Auth Method |
|---------|---------|-------------|
| Proxmox | https://enterprise.proxmox.com/... | Certificate (subscription) |
| GitHub Packages | https://[email protected]/org/repo/... | Personal Access Token |
| GitLab | https://gitlab-ci-token:[email protected]/api/v4/... | Deploy/Personal Token |
| Gemfury | https://[email protected]/apt/yourname/... | API Token |
| Nexus | https://nexus.example.com/repository/apt | Basic auth or token |
Best practices:
1. Always use HTTPS with credentials
2. Use /etc/apt/auth.conf instead of embedding in sources.list
3. Rotate tokens regularly
4. Use minimal-scope tokens (GitHub Fine-Grained, GitLab Deploy Token)
5. Never commit sources.list with credentials to version control
6. Monitor token expiration dates to prevent surprise failures
dpkg: serious warning: files list file for package 'package-name' contains empty filename
How to fix "files list file contains empty filename" in APT
E: Sub-process /usr/bin/dpkg returned an error code (2)
How to fix "Sub-process /usr/bin/dpkg returned an error code (2)" in APT
dpkg-divert: error: rename involves overwriting 'path' with different file
How to fix dpkg-divert rename conflicts in APT
E: Sub-process /usr/bin/dpkg returned an error code (1) during kernel installation
How to fix "dpkg returned an error code (1)" in APT kernel installation
dpkg: dependency problems prevent configuration of triggers
dpkg: dependency problems prevent configuration of triggers in apt