Skip to content

Troubleshooting

Common issues and how to resolve them. Check the backend logs first:

docker compose logs -f backend-api --tail=100

Startup issues

Backend fails to start — JWT_SECRET_KEY missing

Symptom: Container exits immediately with:

RuntimeError: JWT_SECRET_KEY is not set or is using a known-weak default.

Cause: The JWT_SECRET_KEY variable is empty or missing from backend.env.

Fix:

# Generate a strong key
openssl rand -hex 32
# Add to backend.env:
JWT_SECRET_KEY=<generated-value>
docker compose up -d backend-api


ClamAV takes 60+ seconds to start

Symptom: The health endpoint returns "clamav": {"ok": false} for up to 2 minutes after startup.

Cause: ClamAV loads ~800 MB of signatures into memory on first start. This is normal behavior.

Fix: Wait. Subsequent starts are faster because the database is cached in the repos/clamav-db/ volume. If the problem persists after 5 minutes, check:

docker compose logs backend-api | grep -i clamav

Database error: attempt to write a readonly database

Symptom:

sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) attempt to write a readonly database

Cause: A file in repos/auth/ or repos/package-index/ is owned by root instead of appuser (UID 1000). This typically happens after running docker exec commands as root that create files.

Fix:

# Fix auth database
docker exec -u root backend-api chown appuser:appuser /repos/auth/users.db

# Fix package index database (RPM edition)
docker exec -u root backend-api chown appuser:appuser /repos/package-index/packages.db

# Permanent fix: restart (entrypoint.sh re-applies ownership on each start)
docker compose restart backend-api


Upload failures

"Erreur serveur" on package upload

Symptom: The web interface shows "Erreur serveur" after selecting a file.

Cause: Nginx's client_max_body_size is set below the file size. The default in some configurations is 1 MB, which blocks any real package upload.

Diagnosis:

docker compose logs frontend-ui | grep 413
# Or check in the browser Network tab — look for HTTP 413 on the upload request

Fix: The nginx.conf in frontend/nginx.conf should contain:

client_max_body_size 512m;
If missing, add it and rebuild the frontend image:
docker compose build frontend-ui
docker compose up -d frontend-ui


Upload rejected — "Erreur réseau: NetworkError"

Symptom: Upload fails with a network error, before the server even receives the file.

Cause (most common): The frontend was built with REACT_APP_API_URL=http://localhost:8000, causing the browser to try to reach localhost:8000 on the client machine rather than the server.

Diagnosis:

# Check what URL the frontend was built with
docker exec frontend-ui env | grep REACT_APP

Fix: Set the correct URL in .env and rebuild:

# .env
REACT_APP_API_URL=http://192.168.1.100:8000  # or your server's actual address
docker compose build frontend-ui
docker compose up -d frontend-ui


Package stuck in pending_review

Symptom: A package was uploaded successfully but does not appear in the APT/RPM repository. The web interface shows Status: pending_review.

Cause: The CVE scan found vulnerabilities matching the configured review policy. The package is stored but not published until approved.

Fix: 1. Open Security → Review queue in the web interface 2. Review the CVE findings for the package 3. Click Approve to publish, or Reject to remove from the queue

Alternatively via API:

curl -X POST http://localhost:8000/api/v1/security/packages/mypackage/1.0.0/decide \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"decision":"approve","justification":"Vulnerability does not apply to our use case"}'


APT client issues

apt update fails — NO_PUBKEY

Symptom:

W: GPG error: http://repod.example.com:80 jammy InRelease: The following signatures
   couldn't be verified because the public key is not available: NO_PUBKEY ABCD1234...

Cause: The repository's GPG public key is not trusted by the client machine.

Fix:

# Re-import the key from the repository
curl -fsSL http://repod.example.com:80/repos/dists/jammy/InRelease \
  | gpg --dearmor \
  | sudo tee /etc/apt/trusted.gpg.d/repod.gpg > /dev/null

sudo apt update


apt update fails — 404 Not Found

Symptom:

E: Failed to fetch http://repod.example.com:80/repos/dists/jammy/InRelease
   404 Not Found

Cause: The distribution was not initialized, or the distribution name in sources.list does not match a supported codename.

Fix:

# Re-initialize distributions
curl -X POST http://localhost:8000/api/v1/distributions/init \
  -H "Authorization: Bearer $TOKEN"

# Verify the distribution exists
ls /repos/dists/


RPM client issues

dnf install fails — GPG key retrieval failed

Symptom:

warning: /var/cache/dnf/repod/packages/mypackage-1.0.0.rpm: Header V4 RSA/SHA256
Signature, key ID ABCD1234: NOKEY

Cause: The GPG key was not imported before enabling gpgcheck=1.

Fix:

sudo rpm --import http://YOUR_HOST:80/repos/gpg.key
sudo dnf clean all
sudo dnf install mypackage


createrepo_c errors in backend logs

Symptom:

createrepo_c failed (code 1): error: cannot open ...

Cause: The RPM distribution directory does not exist or has wrong permissions.

Fix:

# Re-initialize RPM distributions
curl -X POST http://localhost:8000/api/v1/distributions/init \
  -H "Authorization: Bearer $TOKEN"

# Check permissions
docker exec backend-api ls -la /repos/almalinux9/


Sync / import issues

"Erreur inconnue" during sync (ImportPage)

Symptom: The sync stream shows "Erreur inconnue" immediately when started.

Cause (common): The frontend was built with an older bundle that used incorrect API URLs (missing /api/v1 prefix). The browser is cached on the old build.

Fix: Hard-refresh the browser (Ctrl+Shift+R / Cmd+Shift+R). If the problem persists, clear the browser cache or rebuild the frontend:

docker compose build frontend-ui
docker compose up -d frontend-ui


Index sync returns 0 packages

Symptom: The sync completes without errors but no packages appear in the catalog.

Cause (APT): The external source's Release file cannot be fetched (network restriction, wrong URL, or missing GPG key for the source).

Cause (RPM): The source's repodata/repomd.xml is unreachable, or the SQLite package index database is locked/corrupted.

Diagnosis:

docker compose logs backend-api | grep -i "sync\|error\|package_index"

Fix (SQLite lock):

docker exec -u root backend-api chown appuser:appuser /repos/package-index/packages.db
docker compose restart backend-api


Authentication issues

Login fails with valid credentials

Symptom: The login page returns "Identifiants incorrects" despite using the correct username and password.

Possible causes: 1. The ADMIN_PASSWORD_HASH in backend.env contains unescaped $ signs 2. The users.db was not created (volume permission issue) 3. The account is disabled (is_active: false)

Diagnosis:

# Check if users.db exists and has content
docker exec backend-api python3 -c "
import sqlite3
conn = sqlite3.connect('/repos/auth/users.db')
print(conn.execute('SELECT username, is_active FROM users').fetchall())
"

Fix for hash escaping:

# In backend.env: replace every $ with $$
# Wrong:  ADMIN_PASSWORD_HASH=$2b$12$...
# Correct: ADMIN_PASSWORD_HASH=$$2b$$12$$...


MFA code rejected

Symptom: The TOTP code entered during MFA authentication is rejected despite being generated by the correct authenticator app.

Cause: The server's system clock differs from the client's by more than 30 seconds. TOTP codes are time-based and fail if clocks are not synchronized.

Fix:

# Check server time
docker exec backend-api date

# Sync the host clock (if using NTP)
sudo timedatectl set-ntp true
sudo systemctl restart systemd-timesyncd


Performance issues

Backend is slow or unresponsive

Symptom: API requests take more than 10 seconds, or the health endpoint times out.

Cause (most common): ClamAV or Grype is performing a database update. This is CPU-intensive and can saturate the container's CPU allocation.

Diagnosis:

docker stats backend-api
docker compose logs backend-api | grep -i "freshclam\|grype\|update"

Fix: The default resource limits in docker-compose.yaml are 1.5 CPUs and 2.5 GB RAM. Increase if your hardware allows:

docker-compose.yaml
deploy:
  resources:
    limits:
      memory: 4g
      cpus: "3.0"


Viewing logs

# All containers
docker compose logs -f

# Backend only, last 200 lines
docker compose logs backend-api --tail=200

# Filter for errors
docker compose logs backend-api 2>&1 | grep -i "error\|exception\|traceback"

# Audit log (last 50 entries)
docker exec backend-api tail -n 50 /repos/audit/$(date +%Y-%m-%d).jsonl | python3 -m json.tool