Troubleshooting
This page covers the most common issues you may encounter when running club and how to resolve them.
Server Won’t Start
”SERVER_URL is required”
The server requires a public URL to construct archive download URLs and upload redirects.
Fix: Set the SERVER_URL environment variable to the exact URL clients use — scheme and host must match:
SERVER_URL=https://packages.example.com”JWT_SECRET is required” or “must be at least 32 characters”
The session secret is used to sign tokens and must be at least 32 characters long.
Fix: Generate a secure secret:
JWT_SECRET=$(openssl rand -hex 32)“POSTGRES_URL must be set when DB_BACKEND=postgres”
You set the database backend to PostgreSQL but did not provide a connection URL.
Fix: Either set the PostgreSQL URL or switch back to SQLite:
# Option A: Provide the PostgreSQL URLPOSTGRES_URL=postgres://club:secret@db.example.com:5432/club
# Option B: Use SQLite (default)DB_BACKEND=sqlite“Setup code lost” / cannot complete first-run setup
The first-run setup flow prints a random setup code to the server logs and is IP-pinned after the verify step — only the IP that verified the code can complete setup.
Fix:
- Scan the server logs for the setup code (look for a line printed during startup or the first visit to the setup page).
- Make sure you are browsing from the same IP that was pinned during verify. If your IP changed (VPN, new network), restart the server to issue a fresh code.
- If the log is gone and setup is not yet complete, restart the container — a new code is printed on boot until setup finishes.
Port already in use
Another process is using port 8080 (or your configured port).
Fix:
# Find what's using the portlsof -i :8080
# Either stop that process or change the club listen portLISTEN_PORT=3000Permission denied on database or data directory
The club process does not have write access to the data directory.
Fix:
# Check and fix permissionsls -la /data/chown -R 1000:1000 /data/
# In Docker, ensure the volume is writabledocker run --rm -v club-data:/data alpine ls -la /data/dart pub publish Fails
”Authentication required”
The dart pub client does not have a valid token for your club server.
Fix: Add a token for your server:
dart pub token add https://packages.example.com# When prompted, enter your club API token (club_pat_...)Or set it via environment variable in CI:
export PUB_TOKEN=club_pat_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4dart pub token add https://packages.example.com --env-var PUB_TOKEN“403 Forbidden” / “Not authorized to publish this package”
Your token does not have write scope, or you are not an authorized uploader for the package.
Fix:
- Verify your token has
writescope (web UI → Settings → API Keys). - Ask an existing uploader or admin to add you as an uploader on the package.
- If the package is publisher-owned, ensure you are a member of the publisher.
publish_to pointing at the wrong server
If pubspec.yaml lacks publish_to: or points at https://pub.dev, dart pub publish will try to push to pub.dev instead of your club instance.
Fix: Set publish_to in your package’s pubspec.yaml:
publish_to: https://packages.example.com“Version 2.1.0 already exists”
You are trying to publish a version that already exists with different content.
Fix: Bump the version number in your pubspec.yaml and publish again. Published versions are immutable.
”Invalid package name”
Package names must be lowercase alphanumeric with underscores, 1-64 characters.
Fix: Rename your package in pubspec.yaml to follow the naming rules:
name: my_package # Valid# name: My-Package # Invalid (uppercase, hyphens)# name: my.package # Invalid (dots)Publish uses the wrong pubspec (e.g. example/pubspec.yaml)
club rejects archives that contain a pubspec.yaml anywhere other than the root. If your archive build is pulling in a nested pubspec.yaml (for example from example/), the publish is rejected.
Fix:
- Ensure only the root
pubspec.yamlis included in the archive. - Add nested paths to
.pubignoreif they should not be packaged.
”413: Payload too large”
The tarball exceeds the maximum upload size.
Fix: Either reduce the package size (remove unnecessary files using .pubignore) or increase the server limit:
MAX_UPLOAD_BYTES=524288000 # 500 MBUpload hangs or times out
Upload sessions expire after 10 minutes. Large packages on slow connections may not finish in time.
Fix:
- Check your network connection speed
- Reduce package size using
.pubignore - Increase upload size limit if needed
- Check if a reverse proxy has a smaller timeout or body size limit than club
dart pub get Fails
”Could not resolve package”
The package does not exist on your club server, or the version constraint cannot be satisfied.
Fix:
- Verify the package exists:
curl -H "Authorization: Bearer $TOKEN" https://packages.example.com/api/packages/<package> - Check available versions match your constraint
- Ensure your
pubspec.yamlpoints to the correct hosted URL:
dependencies: my_package: hosted: https://packages.example.com version: ^1.0.0“Connection refused” or “Could not connect”
The club server is not reachable from the client.
Fix:
- Verify the server is running:
curl https://packages.example.com/api/v1/health - Check DNS resolution:
nslookup packages.example.com - Check firewall rules (port 443 for HTTPS, port 8080 for direct access)
- If behind a VPN, ensure the VPN is connected
TLS / SSL certificate errors
HandshakeException: Handshake error in clientFix:
- Ensure your TLS certificate is valid and not expired.
- For self-signed certificates, configure Dart to trust them:
Terminal window export DART_VM_OPTIONS="--root-certs-file=/path/to/ca-cert.pem" - Check that the certificate covers the hostname you are using.
- If you set
TRUST_PROXY=truebut the proxy is not actually terminating TLS,Securecookies and redirect URLs can end up mismatched. Either terminate TLS at the proxy or disableTRUST_PROXY.
Authentication Issues
401: “Authentication required”
Possible causes:
- Token is missing from the request
- Token has been revoked
- Token has expired
Diagnosis:
# Check if your token workscurl -H "Authorization: Bearer $TOKEN" \ https://club.example.com/api/auth/keysIf this returns 401, the token is invalid. Create a new one.
403: “Insufficient permissions”
Possible causes:
- Token has
readscope but the operation requireswriteoradmin - User is not an uploader of the target package
- User is not a member of the publisher
- Scopes were clamped to a lower user role at creation time
Diagnosis:
# List your API keys to check scopescurl -H "Authorization: Bearer $TOKEN" \ https://club.example.com/api/auth/keysCheck the scopes field in the response. Create a new token with the required scopes if needed.
Signed-in web UI loses the session on every refresh
Possible causes:
- Your deployment is serving CLUB over plain HTTP — secure cookies will refuse to stick.
- The browser is blocking third-party cookies (relevant only if CLUB is embedded in an iframe on another domain).
- A reverse proxy in front of CLUB is stripping cookies or the
X-Forwarded-Protoheader withoutTRUST_PROXY=trueset.
Fix: Run CLUB behind HTTPS (see TLS setup). If you’re behind a reverse proxy, set TRUST_PROXY=true.
Database Issues
”database is locked” (SQLite)
SQLite allows only one writer at a time. Under heavy concurrent write load, you may see lock contention.
Possible causes:
- Multiple processes accessing the same database file
- Heavy concurrent publish operations
- Backup process holding a lock
Fix:
- Ensure only one club process accesses the database file.
- The default
busy_timeoutis 5 seconds — most locks resolve within this time. - If the problem persists under normal load, consider running with a larger disk or splitting workloads.
PostgreSQL connection refused
Fix:
- Verify PostgreSQL is running:
pg_isready -h db.example.com - Check the connection URL format:
postgres://user:pass@host:5432/dbname - Verify network connectivity between club and PostgreSQL
- Check PostgreSQL’s
pg_hba.confallows connections from the club host
Out of Disk Space
Symptoms
- Health check reports
blob_storeerror - Publish operations fail with internal errors
- SQLite reports “database or disk is full”
Fix
-
Check disk usage:
Terminal window df -h /datadu -sh /data/* -
Free space immediately:
Terminal window # Clean up temp filesrm -rf /tmp/club-uploads/*# Remove SQLite WAL file (checkpoints first)sqlite3 /data/club.db "PRAGMA wal_checkpoint(TRUNCATE);" -
Long-term solutions:
- Increase disk size
- Switch to S3 or GCS for blob storage
- Delete old/unused package versions via the admin API
- Set up disk usage monitoring and alerts (see Monitoring)
Search Not Returning Results
Newly published packages not appearing in search
The search index is updated during publish finalization. If a package was published but does not appear in search:
-
Wait a moment. The index update happens synchronously during publish, but if you are using Meilisearch, there may be a brief indexing delay.
-
Check if the package is unlisted:
Terminal window curl -H "Authorization: Bearer $TOKEN" \https://packages.example.com/api/packages/<package>/optionsIf
isUnlistedistrue, the package will not appear in search results. -
Rebuild the search index by restarting the server.
Search returns no results at all
-
Verify the search backend is healthy:
Terminal window curl https://packages.example.com/api/v1/healthCheck the
search_indexcomponent in the response. -
If using Meilisearch, verify the Meilisearch instance is running:
Terminal window curl http://meilisearch:7700/health -
If using SQLite FTS5, the index may be corrupted. Rebuild it:
Terminal window sqlite3 /data/club.db "INSERT INTO package_fts(package_fts) VALUES ('rebuild');"
Getting Help
If you cannot resolve an issue:
-
Check the server logs for detailed error messages:
Terminal window docker compose logs club --tail 200 -
Set log level to
debugfor more detail:Terminal window LOG_LEVEL=debug -
Verify your configuration is valid by checking startup logs for validation errors.
-
Open an issue on the GitHub repository with:
- club version (from the health endpoint)
- Storage backend configuration (SQLite/PostgreSQL, filesystem/S3/GCS)
- Relevant log output (redact any secrets)
- Steps to reproduce the issue