Skip to content

Troubleshooting ​

Quick triage ​

bash
# Is it up?
curl -sf http://localhost:8000/ >/dev/null && echo UP || echo DOWN

# What did it say at startup?
docker compose logs --tail=50 brandkit

# Is CSRF live? (must return 400)
curl -s -o /dev/null -w '%{http_code}\n' -X POST http://localhost:8000/upload

# Is the catalogue loading?
curl -s http://localhost:8000/format-info | python3 -m json.tool | head -20

Startup ​

ModuleNotFoundError: No module named 'rembg' ​

Not fatal. The app catches it and disables background removal:

Background removal (rembg) not available. Install with: pip install rembg

Install it (pip install rembg onnxruntime) or accept the loss of the feature.

ImportError: libGL.so.1: cannot open shared object file ​

OpenCV needs system libraries that a bare pip install does not provide.

bash
# Debian / Ubuntu
sudo apt-get install -y libgl1 libglib2.0-0

The Docker image already installs these. If you see it in a container, you have changed the base image.

Address already in use ​

Something else holds port 8000.

bash
lsof -i :8000                 # macOS / Linux
docker compose down           # if it is an old BrandKit container

Or move the host port: "8001:8000" in docker-compose.yml.

Warning: config.json not found. Using default configuration. ​

You started the app from a directory that is not the repo root. load_config() opens config.json by relative path. cd into the project first.

Error: config.json is not valid JSON. Using default configuration. ​

Your edit broke the file. Validate it:

bash
python3 -m json.tool config.json > /dev/null && echo "valid"

The app falls back to built-in defaults rather than crashing, which is why the symptom is "my new format vanished" rather than an error page.

Uploads ​

400 Bad Request — The CSRF token is missing ​

Expected if you are calling /upload with curl or a script. Every POST needs a valid CSRF token; see HTTP endpoints for how to obtain one.

If it happens in the browser, the usual causes are all the same root problem — no stable BRANDKIT_SECRET_KEY:

  • more than one gunicorn worker, each having generated its own ephemeral key
  • the app restarted between page load and submit, regenerating the key
  • (unrelated) cookies blocked for the origin

Check the startup log for No BRANDKIT_SECRET_KEY set. Setting it fixes the first two.

413 Request Entity Too Large ​

The file is over the limit. Two limits are in play:

bash
BRANDKIT_MAX_UPLOAD_MB=32 docker compose up -d      # the app's limit

and your reverse proxy's own body limit (client_max_body_size in Nginx, request_body max_size in Caddy), which must be at least as large. If Flask never logs the request, the proxy rejected it.

File type not allowed ​

Only png, jpg, jpeg, gif, webp are accepted, matched on the extension after the last dot, case-insensitively. Rename or convert:

bash
# SVG is not supported — rasterise first
rsvg-convert -w 2048 logo.svg -o logo.png

Invalid image file ​

The extension was allowed but Pillow could not decode the contents — a corrupt file, or something misnamed. The upload is deleted and the request fails. Verify locally:

bash
python3 -c "from PIL import Image; Image.open('yourfile.png').verify(); print('ok')"

429 Too Many Requests ​

Rate limiting: 5 uploads/minute, 50 requests/hour, 200/day per IP. Wait it out, or adjust the decorators in app.py for a trusted deployment.

Generation ​

It hangs on the first background removal ​

rembg is downloading a ~180 MB ONNX model. Watch for network activity and check ~/.u2net/. Subsequent runs are fast. Pre-seed the directory for offline hosts — see Background removal.

The container is killed mid-generation (exit 137) ​

Out of memory. ONNX Runtime plus a large image plus variations mode will do it.

bash
docker stats brandkit          # watch it climb

Fixes, in order of effectiveness: turn off variations mode, use a smaller source, lower BRANDKIT_MAX_UPLOAD_MB, raise the container memory limit.

504 Gateway Timeout from the proxy ​

A long generation outran the proxy's read timeout. Raise it to 300 s — proxy_read_timeout 300s; in Nginx. See Deployment.

The ICO file did not appear ​

ico is only produced when the favicon format is also selected. If you tick ico without favicon, it is silently dropped from the output types.

Transparency was lost ​

You selected jpg, which has no alpha channel. Use PNG or WebP.

The logo looks tiny in every format ​

Your source has a lot of empty canvas around the mark. Turn on auto-crop with 10–20 px of padding — it trims once and every format benefits.

Generation is slow every single time ​

The disk cache is missing. Either the preprocessing options changed between runs (any change invalidates every entry), or static/uploads/cache/ is not writable:

bash
ls -la static/uploads/
chmod -R u+rwX static/uploads/

In Docker, check that the bind-mounted host directory is writable by the container user.

Disk ​

static/uploads/ has grown to gigabytes ​

Check whether the sweep is running at all — the startup log should say:

Scheduled cleanup started: every 1.0h, deleting files older than 24.0h

If it says Scheduled cleanup disabled via BRANDKIT_CLEANUP_ENABLED, that is why. If it is running but the directory is still large, the retention window is simply longer than your throughput; lower BRANDKIT_RETENTION_HOURS. Details in Performance & caching.

Note the sweep only runs while the container is up. A stopped container leaves the bind-mounted directory untouched.

Still stuck ​

  • Search the issue tracker
  • Open a bug report with the startup log, your Python or Docker version, and the exact steps
  • For anything security-sensitive, use the security policy instead of a public issue