# Troubleshooting Guide Comprehensive troubleshooting for common MyGarage issues, organized by category. --- ## Table of Contents - [Installation Issues](#installation-issues) - [Authentication Problems](#authentication-problems) - [Database Issues](#database-issues) - [VIN Decoder Errors](#vin-decoder-errors) - [File Upload Problems](#file-upload-problems) - [OCR Issues](#ocr-issues) - [Reverse Proxy Problems](#reverse-proxy-problems) - [Performance Issues](#performance-issues) - [Fuel Tracking Problems](#fuel-tracking-problems) - [LiveLink Issues](#livelink-issues) - [Docker Issues](#docker-issues) - [Maintenance Mode and Repair Tools](#maintenance-mode-and-repair-tools) --- ## Installation Issues ### Container Won't Start **Symptoms**: - `docker ps` doesn't show mygarage container - Container immediately stops after `docker-compose up -d` **Diagnosis**: ```bash # Check container logs docker logs mygarage # Check container status docker ps -a | grep mygarage ``` **Common Causes & Solutions**: #### Port Already in Use **Error**: `Bind for 0.0.0.0:8686 failed: port is already allocated` **Fix**: ```yaml # Change port in docker-compose.yml ports: - "8687:8686" # Use 8687 instead ``` Or find what's using port 8686: ```bash sudo lsof -i :8686 # Kill the process or change MyGarage port ``` #### Permission Errors **Error**: `Permission denied: '/data/mygarage.db'` **Fix**: give `./data` to the UID the container runs as. That's 1000 unless you set `user:` in your compose file. ```bash # Default sudo chown -R 1000:1000 ./data # Or match your user: setting, e.g. user: "1001:1001" sudo chown -R 1001:1001 ./data ``` Data copied over from another host keeps its old owner, so this applies after a move too. See [Running as a Different User](Installation#running-as-a-different-user). #### Database Connection Error (PostgreSQL) **Error**: `FATAL: password authentication failed for user "mygarage"` **Fix**: 1. Verify `POSTGRES_PASSWORD` matches `MYGARAGE_DATABASE_URL` 2. Ensure PostgreSQL container is running: `docker ps | grep postgres` 3. Check PostgreSQL logs: `docker logs mygarage-postgres` 4. Reset password: ```bash docker exec mygarage-postgres psql -U postgres -c "ALTER USER mygarage WITH PASSWORD 'new-password';" ``` ### Cannot Access Web Interface **Symptoms**: - Container is running but http://localhost:8686 doesn't load - "Connection refused" error in browser **Diagnosis**: ```bash # Verify container is running docker ps | grep mygarage # Check if MyGarage is listening curl http://localhost:8686/health # Check container logs for errors docker logs mygarage ``` **Solutions**: #### Firewall Blocking Port ```bash # Allow port 8686 (Ubuntu/Debian) sudo ufw allow 8686/tcp # Allow port 8686 (CentOS/RHEL) sudo firewall-cmd --permanent --add-port=8686/tcp sudo firewall-cmd --reload ``` #### Wrong IP Address If accessing from another device: - Don't use `localhost` - use server IP (e.g., `http://192.168.1.100:8686`) - Verify server IP: `ip addr show` or `ifconfig` #### Docker Network Issue ```bash # Restart Docker networking docker-compose down docker-compose up -d ``` ### Database Migration Fails on Startup MyGarage uses a custom migration runner (not Alembic). Migrations live in `backend/app/migrations/NNN_*.py` and are tracked in the `schema_migrations` table; the app stops on the first failed migration. **Fix**: ```bash # Find the failing migration number and error docker logs mygarage # Back up the database before any manual intervention cp data/mygarage.db data/mygarage-backup.db ``` Report the failing migration and error on GitHub, then restore from backup if needed. --- ## Bun Development Issues > **Note**: MyGarage frontend uses Bun (currently 1.4.2; it replaced Node.js in v2.14.3). These troubleshooting steps apply to local development only. ### "Command not found: bun" **Symptoms**: - `bun: command not found` when trying to run `bun install` or `bun dev` **Fix**: ```bash # Install Bun curl -fsSL https://bun.sh/install | bash # Reload shell source ~/.bashrc # or ~/.zshrc # Verify installation bun --version # Should show 1.4.2 or higher ``` ### "lockfile out of sync" **Error**: `error: lockfile had changes, but lockfile is frozen` **Fix**: ```bash # Regenerate lockfile rm bun.lock bun install # Or force install (if you know dependencies haven't changed) bun install --force ``` ### "Module not found" Errors **Symptoms**: - Import errors after `bun install` - Missing dependencies in node_modules **Fix**: ```bash # Clean install cd frontend rm -rf node_modules bun.lock bun install # If still failing, check package.json for typos ``` ### HMR Not Working in Development **Symptoms**: - Changes to React components don't update in browser - Have to manually refresh to see changes **Diagnosis**: ```bash # Check if Vite dev server is running curl http://localhost:3000 ``` **Fixes**: **1. Clear Vite cache**: ```bash rm -rf node_modules/.vite bun dev ``` **2. Hard refresh browser**: - Chrome/Firefox/Edge: `Ctrl+Shift+R` (Windows/Linux) or `Cmd+Shift+R` (Mac) - Safari: `Cmd+Option+R` **3. Restart dev server**: ```bash # Stop server (Ctrl+C), then: bun dev ``` **4. Check browser console**: - Open DevTools (F12) - Look for WebSocket connection errors - HMR uses WebSocket on `ws://localhost:3000` **5. Firewall/proxy issues**: ```bash # Try disabling browser extensions # Check if firewall is blocking WebSocket connections ``` ### Build Fails **Error**: Various TypeScript or build errors **Fix**: ```bash # Clear cache and rebuild cd frontend rm -rf dist node_modules/.vite bun install bun run build # Check for type errors bun run type-check # Check for lint errors bun run lint ``` ### Tests Failing **Error**: Vitest tests fail unexpectedly Use `bun run test:run`. Plain `bun test` starts Bun's own test runner, not Vitest. **Fix**: ```bash # Run tests with verbose output bun run test:run --reporter=verbose # Run specific test file bun run test:run src/pages/__tests__/Dashboard.defaultSort.test.tsx # Clear the Vite and Vitest cache rm -rf node_modules/.vite bun run test:run ``` ### Slow Performance **Symptoms**: - `bun install` taking >30 seconds - `bun dev` slow to start - Build times >10 seconds **Diagnosis**: ```bash # Check Bun version (should be 1.4.2+) bun --version # Check disk space df -h # Check if antivirus is scanning node_modules ``` **Fixes**: 1. Upgrade Bun to latest: `bun upgrade` 2. Exclude `node_modules` from antivirus scans 3. Use SSD instead of HDD for development 4. Close resource-intensive applications --- ## Authentication Problems ### Locked Out (Forgot Password) **Scenario**: Only user, forgot password, can't login **Solutions**: #### Option 1: Reset Database (Loses All Data) ```bash docker-compose stop mygarage rm data/mygarage.db docker-compose start mygarage # Re-register at web interface ``` #### Option 2: Restore from Backup ```bash docker-compose stop mygarage cp data/mygarage-backup.db data/mygarage.db rm -f data/mygarage.db-wal data/mygarage.db-shm docker-compose start mygarage ``` #### Option 3: Set a New Password From the Command Line Settings can't help once nobody can sign in, so set the password in the database. This keeps all your data. First make a hash of the new password inside the container: ```bash docker exec -it mygarage python3 -c "import getpass; from app.services.auth import hash_password; print(hash_password(getpass.getpass('New password: ')))" ``` Then store it on your account, with your username and the hash it printed. SQLite: ```bash docker exec -it mygarage python3 -c "import sqlite3, sys; db = sqlite3.connect('/data/mygarage.db'); n = db.execute('UPDATE users SET hashed_password = ? WHERE username = ?', (sys.argv[1], sys.argv[2])).rowcount; db.commit(); print(n, 'account updated')" 'PASTE_THE_HASH' 'your-username' ``` PostgreSQL: run `UPDATE users SET hashed_password = '...' WHERE username = '...';` with `psql`. Sign in with the new password straight away; no restart is needed. `0 account updated` means the username didn't match (it is case-sensitive). This works for an account that only signs in through SSO too: it gives the account a password, which then works alongside SSO. ### "Invalid Credentials" on Login **Cause**: Wrong username or password. The page says "Incorrect username or password". **Solutions**: - Sign in with your **username**, not your email address (it is case-sensitive) - Check Caps Lock - Try password reset (if admin user exists) - Check container logs for rate limiting: `docker logs mygarage | grep "rate limit"` ### Rate Limited (Too Many Login Attempts) **Error**: `429 Too Many Requests`. SSO sign-in shows "Too many sign-in attempts" on the login page instead. **Cause**: More than 5 sign-in requests in 1 minute from one address **Fix**: Wait a minute, then try again If everyone gets limited at once and MyGarage sits behind a reverse proxy, MyGarage is seeing the proxy as every client. See [Client IP and Rate Limits](Reverse-Proxy#client-ip-and-rate-limits). **Admin Override**: ```bash # Restart container to reset rate limits docker restart mygarage ``` ### OIDC Authentication Fails A refused or failed SSO sign-in returns to the sign-in page with a sentence saying why. When it says single sign-on didn't work, `docker logs mygarage` has the cause. **Error**: `Invalid redirect URI` **Cause**: Redirect URI mismatch between MyGarage and OIDC provider **Fix**: 1. Copy the **Redirect URI** from MyGarage (Settings → System → OIDC section) 2. Add this exact URI to your OIDC provider's allowed redirect URIs 3. Ensure you don't mix http/https 4. The path should end with `/auth/oidc/callback` **Error**: `OIDC claims missing email` in the log **Cause**: OIDC provider not returning email **Fix**: 1. Ensure `email` scope is requested 2. Configure OIDC provider to include `email` in ID token claims 3. Check OIDC provider documentation for claim configuration --- ## Database Issues ### "Database is Locked" (SQLite) **Symptoms**: - Error: `database is locked` Since v2.30, MyGarage runs SQLite in WAL mode with a 30-second `busy_timeout`, so this error should not occur under normal concurrent writes. If it still appears: - Ensure the data volume is on local storage — network filesystems (NFS/SMB) don't implement SQLite locking reliably. - Check the disk isn't full: `df -h`. - If the database is corrupted, see [Database Corruption](#database-corruption) below. ### Database Corruption **Symptoms**: - Errors mentioning "malformed" or "corrupt" - Missing data - Container crashes on startup **Diagnosis** (the image has no `sqlite3` command, so this uses Python): ```bash # Check SQLite integrity; "ok" means no corruption found docker exec mygarage python3 -c "import sqlite3; print(sqlite3.connect('/data/mygarage.db').execute('PRAGMA integrity_check').fetchone()[0])" ``` **If corrupted**, restore from backup: ```bash docker-compose stop mygarage cp data/mygarage-backup.db data/mygarage.db rm -f data/mygarage.db-wal data/mygarage.db-shm docker-compose start mygarage ``` ### PostgreSQL Connection Timeout **Error**: `could not connect to server: Connection timed out` **Diagnosis**: ```bash # Check PostgreSQL is running docker ps | grep postgres # Test connection docker exec mygarage-postgres psql -U mygarage -c "SELECT 1;" # Check PostgreSQL logs docker logs mygarage-postgres ``` **Solutions**: #### PostgreSQL Not Started ```bash docker-compose up -d postgres # Wait for PostgreSQL to fully start (check logs) docker-compose up -d mygarage ``` #### Wrong Hostname ```yaml # Verify hostname matches container name environment: - MYGARAGE_DATABASE_URL=postgresql+asyncpg://user:pass@mygarage-postgres:5432/mygarage # ^^^^^^^^^^^^^^^^ # Must match container name ``` #### Network Issue ```bash # Ensure containers are on same network docker network inspect mygarage_default # Look for both containers ``` --- ## VIN Decoder Errors ### "Invalid VIN" Error **Causes**: - VIN not 17 characters - VIN contains invalid characters (O, I, Q not allowed) - Incorrect VIN entered **Solution**: - Verify VIN from registration or door jamb sticker - VINs are always 17 characters (no spaces) - Letters O, I, Q are never used (to avoid confusion with 0, 1, Q) ### "VIN Not Found in Database" **Causes**: - Non-US vehicle (NHTSA database is US-only) - Vehicle older than 1981 (pre-standardized VINs) - Commercial vehicle, RV, or motorcycle (limited data) **Solution**: Use manual entry instead of VIN decoder ### VIN Decoder Returns Partial Data **Expected Behavior**: NHTSA database doesn't have complete data for all vehicles. **Solution**: - Fill in missing fields manually after decoding - Edit vehicle after creation to add trim, color, etc. ### "VIN Decoder Service Unavailable" **Error**: `503 Service Unavailable` or timeout **Cause**: NHTSA vPIC API is down or slow **Solutions**: 1. Wait 5-10 minutes and try again 2. Use manual entry 3. Check NHTSA API status: https://vpic.nhtsa.dot.gov/api/ --- ## File Upload Problems ### Upload Fails (No Error Message) **Diagnosis**: ```bash # Check container logs docker logs mygarage | grep -i "upload\|error" # Check disk space df -h | grep /srv/raid0 ``` **Common Causes**: #### File Too Large **Limits**: - Photos: 10MB - Documents (PDF): 25MB **Solution**: Compress file before uploading - Images: Use TinyPNG, ImageOptim, or similar - PDFs: Use Adobe Acrobat or online PDF compressor #### Disk Full **Error in logs**: `No space left on device` **Solution**: ```bash # Check disk usage df -h # Clear Docker cache docker system prune -a --volumes # Move data to larger disk ``` #### Browser Timeout (Slow Connection) **Solution**: - Use wired connection instead of Wi-Fi - Compress files before uploading - Upload one file at a time ### "Invalid File Type" Error **Cause**: Unsupported file extension **Supported Types**: - Photos: JPG, JPEG, PNG, WEBP, HEIC, HEIF - Documents: PDF, DOC, DOCX, XLS, XLSX, TXT, CSV, JPG, JPEG, PNG - Receipts and attachments: PDF, JPG, JPEG, PNG, GIF **Solution**: Convert file to supported format - .tiff → .jpg or .pdf --- ## OCR Issues OCR only fills in a form from an upload: **Import from PDF** on an insurance policy, **Upload Window Sticker** on a vehicle, and, if you turn on the LLM receipt parser in **Settings → Integrations**, **Parse receipt** on a fuel entry. It reads typed English text. Stored documents are never read or indexed (see [Documents](Documents#ocr)). A window sticker upload isn't scanned while **Enable OCR Processing** is off in **Settings → File Management**: the file is saved and the sticker's details are left as they are. ### OCR Not Extracting Text **Possible Causes**: #### Low Quality Scan **Solution**: - Re-scan at 300 DPI or higher - Ensure good lighting (no shadows, glare) - Use scanner instead of phone camera if possible - Keep document flat (not wrinkled or curved) #### Handwritten Document **Expected Behavior**: OCR reads typed text, not handwriting **Solution**: Fill in the form by hand #### Non-English Text **Current Limitation**: OCR is configured for English only **Workaround**: Fill in the form by hand ### Extracted Text is Garbled **Causes**: - Poor scan quality - Faded thermal receipt paper - Low contrast (light text on light background) **Solutions**: - Increase scan contrast before uploading - Re-scan with higher resolution - Fill in the form by hand ### OCR Takes Too Long **Expected**: OCR can take 10-30 seconds for multi-page PDFs **If longer than 2 minutes**: ```bash # Check CPU usage docker stats mygarage # If CPU is maxed, increase Docker resources # Docker Desktop → Settings → Resources → CPUs (increase to 2+) ``` --- ## Reverse Proxy Problems ### "502 Bad Gateway" (Nginx/Caddy) **Cause**: Reverse proxy can't reach MyGarage **Diagnosis**: ```bash # Verify MyGarage is running docker ps | grep mygarage # Test MyGarage health endpoint curl http://localhost:8686/health # Check reverse proxy logs sudo tail -f /var/log/nginx/error.log ``` **Solutions**: #### Wrong Upstream Address **Nginx**: ```nginx # If MyGarage is Docker container on same host location / { proxy_pass http://127.0.0.1:8686; # NOT localhost:8686 # ... } # If using Docker networks location / { proxy_pass http://mygarage:8686; # Container name # ... } ``` #### Network Isolation If reverse proxy is in Docker, ensure same network: ```yaml networks: - traefik-proxy # Both reverse proxy and MyGarage must be on this network ``` ### "Too Many Redirects" Loop **Cause**: Both reverse proxy and MyGarage forcing HTTPS redirects **Solution**: Ensure `X-Forwarded-Proto` header is set correctly **Nginx**: ```nginx proxy_set_header X-Forwarded-Proto $scheme; ``` **Traefik**: Handled automatically ### SSL Certificate Errors #### "Certificate not valid" **Cause**: Let's Encrypt certificate failed to generate **Diagnosis**: ```bash # Check Certbot logs (Nginx) sudo cat /var/log/letsencrypt/letsencrypt.log # Check Traefik logs docker logs traefik ``` **Common Issues**: **Domain Not Resolving**: ```bash # Verify DNS nslookup garage.example.com # Ensure A record points to your server IP ``` **Port 80 Not Open** (required for Let's Encrypt HTTP challenge): ```bash sudo ufw allow 80/tcp ``` **Rate Limit Hit**: - Let's Encrypt allows 50 certs per domain per week - Use staging environment for testing - Wait 7 days for limit reset #### "NET::ERR_CERT_AUTHORITY_INVALID" **Cause**: Using Let's Encrypt staging certificates **Solution**: Switch to production: **Certbot**: ```bash sudo certbot --nginx -d garage.example.com # Remove --staging flag ``` **Traefik**: ```yaml # Remove staging certificatesResolvers config certificatesResolvers: letsencrypt: acme: # caServer: https://acme-staging-v02.api.letsencrypt.org/directory # Remove this line ``` --- ## Performance Issues ### Slow Page Loads **Diagnosis**: ```bash # Check resource usage docker stats mygarage # Check database size ls -lh data/mygarage.db ``` **Common Causes & Solutions**: #### Database Too Large (SQLite) **If > 500MB or > 10,000 records**: 1. Vacuum database: ```bash docker exec mygarage python3 -c "import sqlite3; sqlite3.connect('/data/mygarage.db').execute('VACUUM')" ``` 2. Migrate to PostgreSQL (see [Database Configuration](Database-Configuration)) #### Low Docker Resources **Docker Desktop → Settings → Resources**: - CPU: Increase to 2+ cores - Memory: Increase to 1GB+ #### Slow Disk (HDD) **Solution**: Move `/data` volume to SSD #### Too Many Photos/Documents **Solution**: - Compress photos before uploading - Delete old documents no longer needed - Archive old vehicles (moves data out of active queries) ### High CPU Usage **Normal**: 5-15% idle, 20-40% during OCR processing **If consistently > 60%**: **Diagnosis**: ```bash # Check what process is using CPU docker exec mygarage top ``` **Possible Causes**: - Runaway background job (check logs) - Resource-intensive query (check database) - Restart container: `docker restart mygarage` --- ## Fuel Tracking Problems ### MPG Not Calculating **Cause**: Requires 2+ full tank fill-ups **Solution**: 1. Verify first fill-up has **Full Tank Fill-up** checked 2. Add second fill-up with **Full Tank Fill-up** checked 3. MPG will calculate on second+ fill-up ### MPG Seems Wrong **Too High** (e.g., 60 MPG on a truck): - Missed fill-up between entries (shows 2x distance on 1 tank) - Odometer entry error (typo) - Gallons entry error (half the actual amount) **Too Low** (e.g., 10 MPG on a sedan): - Partial fill mistakenly marked as **Full Tank Fill-up** - Odometer recorded incorrectly **Fix**: Edit recent fill-ups to correct data --- ## LiveLink Issues ### Device Not Discovered **Symptoms**: - WiCAN configured but not appearing in MyGarage - Device list shows no unlinked devices **Diagnosis**: ```bash # Check MyGarage logs for LiveLink messages docker logs mygarage 2>&1 | grep -i "livelink\|wican\|ingest" # Test ingestion endpoint directly curl -X POST https://mygarage.local/api/v1/livelink/ingest \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"autopid_data":{"TEST":1},"config":{},"status":{"device_id":"test123"}}' ``` **Solutions**: #### Token Mismatch **Cause**: WiCAN token doesn't match MyGarage token **Fix**: 1. Go to Settings → Integrations, open the **WiCAN** tab on the LiveLink card and click **WiCAN settings** 2. The token is shown only once, when generated. If you don't have it, click **Generate** for a new one (the old one stops working) 3. In WiCAN web UI, set Authorization header to `Bearer YOUR_TOKEN` (include "Bearer " prefix) #### Incorrect Endpoint URL **Cause**: WiCAN sending to wrong URL **Fix**: - Verify URL: `https://your-domain/api/v1/livelink/ingest` - Include `/api/v1/livelink/ingest` path - Use HTTPS if reverse proxy requires it - Check for trailing slashes #### Network Connectivity **Cause**: WiCAN can't reach MyGarage **Fix**: - Verify WiCAN is connected to WiFi (check device web UI) - Ensure WiCAN and MyGarage are on same network (or properly routed) - Check firewall rules allow WiCAN to reach MyGarage port - Test: `curl http://mygarage-ip:8686/health` from WiCAN network segment #### LiveLink Disabled **Cause**: LiveLink integration turned off. While it is off, nothing is stored from any source (WiCAN, Torque or MQTT), no new device is discovered, and SD-card backfill does not run. **Fix**: - Go to Settings → Integrations and click the **LiveLink settings** gear on the LiveLink card - Turn on **Enable LiveLink** ### No Telemetry Data **Symptoms**: - Device discovered but no gauges/data on LiveLink tab - Charts show no data points **Diagnosis**: ```bash # Check for telemetry processing docker logs mygarage 2>&1 | grep -i "telemetry\|stored" # Check database for telemetry entries docker exec mygarage python3 -c "import sqlite3; print(sqlite3.connect('/data/mygarage.db').execute('SELECT COUNT(*) FROM vehicle_telemetry').fetchone()[0])" ``` **Solutions**: #### Device Not Linked to Vehicle **Cause**: Telemetry only stored for linked devices **Fix**: 1. Go to Settings → Integrations and open the device's tab on the LiveLink card 2. Click its settings button (for example **WiCAN settings**) and find the device 3. Use the vehicle dropdown to link it to a vehicle #### AutoPID Not Configured **Cause**: WiCAN not polling any PIDs **Fix**: 1. Access WiCAN web UI 2. Go to AutoPID configuration 3. Add PIDs to poll (use vehicle profile or custom PIDs) 4. Save and reboot WiCAN #### Raw CAN Frames Instead of Decoded Data **Cause**: WiCAN publishing raw CAN frames instead of decoded telemetry **Expected format** (decoded): ```json {"odometer": 87458.0, "engine coolant temperature": 91.5} ``` **Wrong format** (raw): ```json {"bus":"0","type":"rx","frame":[{"id":631,"dlc":8,"data":"FF0000010000AAA7"}]} ``` **Fix**: - In WiCAN AutoPID settings, ensure MQTT/HTTP output uses decoded format - Check WiCAN documentation for your firmware version ### MQTT Connection Failed **Symptoms**: - The **Mosquitto** tab on the LiveLink card says **Broker not connected** - **Test** fails **Diagnosis**: ```bash # Check if broker is reachable nc -zv 192.168.1.50 1883 # your broker's address # Check MyGarage logs for MQTT errors docker logs mygarage 2>&1 | grep -i "mqtt" # Check broker logs (if using Mosquitto) docker logs mosquitto ``` **Solutions**: #### Broker Not Running **Fix**: ```bash docker ps | grep mosquitto # If not running: docker start mosquitto ``` #### Wrong Host/Port **Fix**: - Verify broker IP address is correct - Default port is 1883 (or 8883 for TLS) - Use IP address instead of hostname if DNS isn't working #### Authentication Failed **Cause**: Broker requires username/password **Fix**: 1. Open the **Mosquitto** tab on the LiveLink card, click **Mosquitto settings**, and enter **Username** and **Password** 2. Verify credentials match broker configuration 3. Click **Save**, then **Test** (it uses the saved settings) #### Firewall Blocking Port **Fix**: ```bash # Allow MQTT port sudo ufw allow 1883/tcp ``` #### TLS Mismatch **Cause**: Broker requires TLS but MyGarage not configured for it (or vice versa) **Fix**: - Match TLS setting to broker configuration - If broker requires TLS, enable **Use TLS/SSL** in **Mosquitto settings** - If broker doesn't support TLS, disable **Use TLS/SSL** ### Phantom Devices **Symptoms**: - Unknown device IDs appear that you don't recognize - Devices with similar-but-wrong IDs to your actual device **Cause**: MQTT brokers retain messages, and before v3.10.0 MyGarage created a device from an old retained message when it subscribed. Retained messages are ignored now (apart from a device's last-will `offline`), so they no longer create devices. **Solution**: delete the phantom devices left by an earlier version. Go to Settings → Integrations, open the source's tab on the LiveLink card, click its settings button and delete them. ### Drive Sessions Not Recording **Symptoms**: - Vehicle runs but no drive sessions created - Sessions show as one long session **Diagnosis**: ```bash # Check for session events docker logs mygarage 2>&1 | grep -i "session" # Check ECU status in database docker exec mygarage python3 -c "import sqlite3; [print(*r) for r in sqlite3.connect('/data/mygarage.db').execute('SELECT device_id, ecu_status, last_seen FROM livelink_devices')]" ``` **Solutions**: #### No Speed or Odometer MyGarage Recognises **Cause**: Since v3.3.0 a drive is recorded only when the vehicle moves: a speed of 5 km/h (about 3 mph) or more, or an odometer reading that goes up. A device that never reports either records no drives, and LiveLink settings shows a warning naming it. **Fix**: - Add vehicle speed or odometer to the WiCAN's AutoPID list - Check the container log for the readings the device actually sends - As a last resort, set **How drives are detected** to **By device connection (legacy)**, which opens a drive whenever the device connects #### Drives Split or Merged Wrongly A drive ends when the vehicle has sat still for **Stop before a new drive** (default 15 minutes, in LiveLink settings), or when the device has sent nothing for 5 minutes. Movement that comes back inside the stop window carries on the same drive, even after the engine was switched off. So a fuel stop stays one drive and a longer stop becomes two: raise **Stop before a new drive** if your stops get split, lower it if separate trips get merged. **Session Grace Period** (default 60 seconds) delays ending a drive after WiFi drops. See [LiveLink](LiveLink). ### Odometer Not Syncing **Symptoms**: - Telemetry working but odometer not updating - No LiveLink badge on odometer entries **Causes**: #### Vehicle Doesn't Support Odometer PID **Reality**: Many vehicles don't expose odometer via standard OBD2 PID (0xA6) **Fix**: 1. Search for manufacturer-specific odometer PIDs for your vehicle 2. Add custom PID to WiCAN AutoPID configuration 3. Some vehicles require proprietary PIDs (Honda, Mitsubishi, etc.) #### Odometer PID Not Configured **Fix**: 1. Check WiCAN AutoPID configuration 2. Add odometer PID if not present 3. Vehicle profiles may or may not include odometer #### Device Not Linked **Cause**: Odometer sync requires device linked to vehicle **Fix**: Link device to vehicle (see [Device Not Linked to Vehicle](#device-not-linked-to-vehicle)) ### Alerts Not Sending **Symptoms**: - Threshold exceeded but no notification - Device offline but no alert **Diagnosis**: ```bash # Check alert settings and delivery docker logs mygarage 2>&1 | grep -i "alert\|notif" ``` **Solutions**: #### Notification Backend Not Configured **Fix**: - MyGarage supports ntfy, Gotify, Pushover, Slack, Discord, Telegram, Matrix, and email. Configure at least one under Settings → Notifications and send a test. #### Alert Cooldown Active **Cause**: 30-minute cooldown prevents repeated alerts **Expected**: Same alert won't fire again until cooldown expires #### Threshold Not Set **Fix**: - Alert lines can be set in Settings only for sensors that offer them, such as a propane tank - Open its tab on the LiveLink card, click its settings button, and fill **Low** or **Critical** under **Alerts** #### Alert Type Disabled **Fix**: - Check the alert toggles under **LiveLink settings** (the gear on the LiveLink card) - Ensure specific alert type (offline, threshold, firmware) is enabled --- ## Docker Issues ### "Permission Denied" Errors **Error**: `permission denied: '/data/mygarage.db'` **Cause**: Data directory not owned by the container user (UID 1000, or whatever `user:` is set to) **Solution**: ```bash # Change ownership to the container's UID:GID (1000:1000 by default) sudo chown -R 1000:1000 ./data ``` Running as a different UID? See [Running as a Different User](Installation#running-as-a-different-user). ### Cannot Pull Docker Image **Error**: `Error response from daemon: Get https://ghcr.io/v2/: unauthorized` **Cause**: Docker not logged in (if using private registry) **Solution**: ```bash # MyGarage is public - no login required docker pull ghcr.io/homelabforge/mygarage:latest # If still fails, check internet connection ping ghcr.io ``` ### Docker Compose Command Not Found **Error**: `docker-compose: command not found` **Cause**: Docker Compose not installed **Solution**: ```bash # Install Docker Compose (Linux) sudo apt install docker-compose # Or use `docker compose` (Compose V2) docker compose up -d ``` --- ## Maintenance Mode and Repair Tools Added in v3.3.0. The repo's `backend/tools/` ships in the runtime image as `/app/tools`, with the scripts that repair LiveLink data in place. Before v3.3.0 the directory was built and then discarded, so every one of these commands failed with `can't open file`. **Maintenance mode.** Setting `MYGARAGE_MAINTENANCE_MODE=1` starts the instance for migrations only: the scheduler, MQTT subscriber and Telegram fuel commands do not start, the ingest endpoints and the admin SD-card backfill answer 503, and the telemetry writers refuse. The rest of the admin API stays open, so you can watch a repair and turn the mode back off. It exists because these tools have to see the data exactly as a migration left it, before any new reading arrives, and a dongle replaying its buffer mid-repair would corrupt the result. ``` # add to the service's environment, then restart MYGARAGE_MAINTENANCE_MODE=1 ``` **The tools.** | Tool | What it does | |------|--------------| | `backfill_livelink_odometer.py` | Rebuilds odometer records lost to the pre-v3.3.0 units bug, from telemetry already on disk | | `normalize_telemetry_odometer_units.py` | Converts stored odometer telemetry to canonical kilometres | | `fix_session_odometer_units.py` | Converts drive-session odometers recorded in the wrong unit | | `recompute_session_aggregates.py` | Recomputes each session's distance, speed and RPM from the telemetry inside its own window. Since v3.10.0 a reading shared by two touching drives counts toward the earlier one only, so a rerun can change those drives' figures | | `repair_wican_odometer_unit.py` | Repairs one device's odometer read in the wrong unit (WiCAN `--to km` or `--to mi`; Torque `--key TORQUE_ODOMETER --to km`), on its own, not in the sequence below. Dry run until `--apply`; run after v3.10.0's first start. See [Odometer Integration](LiveLink#odometer-integration) | | `oidc_allow_relink.py` | Allows a one-time SSO relink for an account whose identity-provider account was re-created, for up to 30 minutes (`--minutes 0` cancels). Writes at once, with no dry run: `docker exec -w /app mygarage python tools/oidc_allow_relink.py --username X`. See [Relinking an SSO Account](Authentication#relinking-an-sso-account) | Run the four LiveLink tools in that order. The order matters: the backfill reads telemetry as the device reported it, so it has to run before the converters make the history metric. The dry-run default and exit 2 rules below cover those four tools only. Each is **dry run by default**, works against the instance's own configured database (`--db` only if you need another), supports SQLite and PostgreSQL, and reads from the data whether its work is still outstanding, so running one twice cannot double a value. Where that cannot be decided safely the tool **exits 2** rather than guess, and a dry run that refused something exits 2 as well, so a script can gate `--apply` on it. **Expect `recompute_session_aggregates.py` to lower old drive distances, often sharply.** A session's distance used to be the gap between the vehicle's newest odometer reading at each end, so distance driven while no session was open was charged to whichever session opened next. Your vehicle's mileage is unaffected: odometer records are a separate table and nothing here writes to it. **How far back a repair reaches.** All four work from telemetry still on disk, and telemetry is pruned to `livelink_telemetry_retention_days` (default 90). Anything older is gone. If you want more history repaired, raise that setting and let data age out more slowly *before* upgrading. Full detail, including the exact `docker exec` sequence, is in the v3.3.0 release notes. --- ## Getting More Help ### Enable Debug Mode **Temporary Debug**: ```yaml environment: - MYGARAGE_DEBUG=true ``` Restart and check logs: `docker logs mygarage` This variable is the only way to turn on debug logging. The old **Debug Mode** switch in Settings changed nothing and has been removed. **WARNING**: Debug mode: - Exposes detailed error messages (may leak internal paths) - Disables secure cookie flag (allows HTTP) - **Never enable in production** ### Collect Diagnostic Information When reporting issues, include: ```bash # MyGarage version docker inspect mygarage | grep "org.opencontainers.image.version" # Container logs (last 100 lines) docker logs --tail 100 mygarage # Container status docker ps -a | grep mygarage # Docker Compose config (redact secrets!) cat docker-compose.yml # System info uname -a docker --version ``` MyGarage keeps the Telegram bot token, Discord and Slack webhook URLs, and TomTom and Google Places API keys out of its logs. Older versions could write them there, so check older logs before posting them. ### Report Issues 1. Search existing issues: [GitHub Issues](https://github.com/homelabforge/mygarage/issues) 2. If not found, create new issue: [Bug Report](https://github.com/homelabforge/mygarage/issues/new/choose) 3. Include diagnostic info above --- ## Advanced Troubleshooting ### Access MyGarage Container Shell ```bash # Bash shell in running container docker exec -it mygarage bash # Check environment variables env | grep MYGARAGE # Check file permissions ls -la /data ``` ### Reset MyGarage to Defaults **Complete Reset** (WARNING: Deletes all data): ```bash # Stop and remove container docker-compose down # Delete data directory rm -rf ./data # Recreate mkdir ./data sudo chown 1000:1000 ./data # or your user: UID:GID # Start fresh docker-compose up -d ``` ### Restore from Backup **SQLite**: ```bash docker-compose stop mygarage cp data/mygarage-backup.db data/mygarage.db rm -f data/mygarage.db-wal data/mygarage.db-shm docker-compose start mygarage ``` **PostgreSQL**: ```bash # Restore from SQL dump docker exec -i mygarage-postgres psql -U mygarage mygarage < backup.sql ``` --- **Still Having Issues?** - **Community Help**: [GitHub Discussions](https://github.com/homelabforge/mygarage/discussions) - **Check FAQ**: [FAQ](FAQ) - **Report Bugs**: [GitHub Issues](https://github.com/homelabforge/mygarage/issues) - **Security Issues**: [Security Advisories](https://github.com/homelabforge/mygarage/security/advisories/new)