Skip to main content
QFieldCloud includes built-in support for debugging with debugpy, primarily designed for VSCode but compatible with other debugpy-compatible IDEs.

Setup Debugging Environment

Use Local Development Override

Ensure your .env file includes the local development override:
DEBUG=1
COMPOSE_FILE=docker-compose.yml:docker-compose.override.local.yml:docker-compose.override.standalone.yml
The docker-compose.override.local.yml file configures debugpy for both app and worker_wrapper services.

Debugpy Ports

Default debugpy ports (configured in .env):
  • app: 5678 (mapped to DEBUG_APP_DEBUGPY_PORT)
  • worker_wrapper: 5679 (mapped to DEBUG_WORKER_WRAPPER_DEBUGPY_PORT)
  • qgis: 5680 (mapped to DEBUG_QGIS_DEBUGPY_PORT, optional)

VSCode Setup

Launch Configuration

The repository includes .vscode/launch.json with three debug configurations:

1. Attach to App

{
  "name": "QFieldCloud Debug (Attach) - app",
  "type": "debugpy",
  "request": "attach",
  "connect": {
    "host": "localhost",
    "port": 5678
  },
  "pathMappings": [
    {
      "localRoot": "${workspaceFolder}/docker-app",
      "remoteRoot": "/usr/src/app"
    }
  ]
}

2. Attach to Worker Wrapper

{
  "name": "QFieldCloud Debug (Attach) - worker_wrapper",
  "type": "debugpy",
  "request": "attach",
  "connect": {
    "host": "localhost",
    "port": 5679
  },
  "pathMappings": [
    {
      "localRoot": "${workspaceFolder}/docker-app",
      "remoteRoot": "/usr/src/app"
    }
  ]
}

3. Attach to QGIS Worker

{
  "name": "QFieldCloud Debug (Attach) - qgis",
  "type": "debugpy",
  "request": "attach",
  "connect": {
    "host": "localhost",
    "port": 5680
  },
  "pathMappings": [
    {
      "localRoot": "${workspaceFolder}/docker-qgis",
      "remoteRoot": "/usr/src/app"
    }
  ]
}

Start Debugging

  1. Start the services:
docker compose up -d
  1. In VSCode, press F5 or go to Run and Debug panel
  2. Select the appropriate configuration (app or worker_wrapper)
  3. Click the green play button or press F5
The debugger will attach to the running container. You can now set breakpoints in your code.

Debugging Modes

Mode 1: Always-On Debugging (Default)

By default, debugpy is running in the background, ready to accept connections. This mode doesn’t pause execution.
  • Set breakpoints in VSCode
  • Attach the debugger with F5
  • Trigger the code path (make an API request, run a job, etc.)
  • Debugger will pause at breakpoints

Mode 2: Wait for Debugger

To pause execution before any code runs, add this snippet to your code:
import debugpy
debugpy.listen(("0.0.0.0", 5680))
print("debugpy waiting for debugger... 🐛")
debugpy.wait_for_client()  # Execution pauses here
Place this at the top of:
  • docker-app/qfieldcloud/wsgi.py for app startup
  • docker-app/worker_wrapper/wrapper.py for worker startup
  • Any management command or view

Mode 3: Debug Specific Commands

Prefix commands with the debugpy invocation:
# Debug a management command
docker compose run --rm -p 5680:5680 app \
  python -m debugpy --listen 0.0.0.0:5680 --wait-for-client \
  manage.py test

# Debug the worker wrapper
docker compose run --rm -p 5681:5681 worker_wrapper \
  python -m debugpy --listen 0.0.0.0:5681 --wait-for-client \
  manage.py dequeue
Then attach the debugger before the command executes.

Mode 4: Persistent Wait-for-Client

Modify docker-compose.override.local.yml to always wait:
services:
  app:
    command: python3 -m debugpy --listen 0.0.0.0:5678 --wait-for-client manage.py runserver 0.0.0.0:8000
Now the app won’t start until you attach the debugger.

Debug Vendor Modules

To debug code in third-party packages (installed via pip):

1. Copy Site Packages

Copy the Python packages from the container to your host:
docker compose cp app:/usr/local/lib/python3.10/site-packages/ docker-app/site-packages

2. Update Path Mappings

In .vscode/launch.json, uncomment the vendor path mapping:
{
  "pathMappings": [
    {
      "localRoot": "${workspaceFolder}/docker-app",
      "remoteRoot": "/usr/src/app"
    },
    // Uncomment to debug vendor modules
    {
      "localRoot": "${workspaceFolder}/docker-app/site-packages",
      "remoteRoot": "/usr/local/lib/python3.10/site-packages/"
    }
  ],
  "justMyCode": false  // Also enable this
}

3. Re-copy After Dependency Changes

Important: Re-run the copy command whenever requirements*.txt files change:
docker compose cp app:/usr/local/lib/python3.10/site-packages/ docker-app/site-packages

Debugging QGIS Workers

Debugging QGIS workers is more complex because they run in separate Docker containers.

Set DEBUG_QGIS_DEBUGPY_PORT

In .env, set the QGIS debug port:
DEBUG_QGIS_DEBUGPY_PORT=5680
This makes the QGIS container wait for a debugger on port 5680.

Mount Local Code

To debug your local QGIS worker code, set:
DEBUG_QGIS_WORKER_HOST_PATH="${PWD}/docker-qgis"
This mounts:
  • docker-qgis/qfc_worker
  • docker-qgis/entrypoint.py
  • docker-qgis/libqfieldsync (if present)
  • docker-qgis/qfieldcloud-sdk-python (if present)

Attach to QGIS Worker

  1. Trigger a job that spawns a QGIS worker
  2. The worker will pause waiting for debugger
  3. In VSCode, select QFieldCloud Debug (Attach) - qgis
  4. Press F5
  5. Set breakpoints in docker-qgis/qfc_worker/*.py

Debugging Tips

Set Breakpoints

Click in the gutter (left of line numbers) or press F9.

Step Through Code

  • F10: Step over (execute current line)
  • F11: Step into (enter function)
  • Shift+F11: Step out (exit function)
  • F5: Continue execution

Inspect Variables

Hover over variables or use the Variables panel in VSCode.

Evaluate Expressions

Use the Debug Console to run Python expressions:
>>> user.username
'testuser'
>>> Project.objects.count()
5

Conditional Breakpoints

Right-click a breakpoint and set a condition:
user.is_superuser == True

Log Points

Add a log point instead of a breakpoint to log without pausing: Right-click in the gutter → Add Logpoint
User ID: {user.id}

Common Issues

Debugger Won’t Attach

Problem: “Timed out waiting for debugger connection” Solutions:
  1. Check that the service is running:
docker compose ps
  1. Verify the port mapping:
docker compose port app 5678
  1. Check debugpy is listening:
docker compose logs app | grep debugpy
  1. Restart the service:
docker compose restart app

Breakpoints Not Hitting

Problem: Debugger attached but breakpoints don’t trigger. Solutions:
  1. Check path mappings: Ensure localRoot and remoteRoot match.
  2. Verify file is executed: Add a print() statement to confirm.
  3. Check source code is mounted:
docker compose exec app cat /usr/src/app/qfieldcloud/core/views.py
  1. Reload the module: Restart the service after code changes:
docker compose restart app

Container Exits Immediately

Problem: Container exits when using --wait-for-client. Solution: Attach the debugger quickly, or increase the timeout. Alternatively, add a long sleep:
import time
print("Waiting for debugger...")
time.sleep(60)

Performance Issues

Problem: Debugger is slow or unresponsive. Solutions:
  1. Disable justMyCode: false if not needed
  2. Reduce log verbosity in settings.py
  3. Use conditional breakpoints to reduce hits
  4. Restart the container

Debugging Tests

To debug a test:
docker compose run --rm -p 5680:5680 app \
  python -m debugpy --listen 0.0.0.0:5680 --wait-for-client \
  manage.py test --keepdb qfieldcloud.core.tests.test_permission.QfcTestCase.test_collaborator_project_takeover
Then attach with VSCode and set breakpoints in the test file.

Django Debug Toolbar

For web-based debugging, Django Debug Toolbar is enabled in development. Access: Visit any page at https://localhost and look for the debug toolbar on the right side. Features:
  • SQL queries and performance
  • Template rendering time
  • Cache hits/misses
  • Request headers and session data
Configuration: See settings.py:707-709:
DEBUG_TOOLBAR_CONFIG = {
    "SHOW_TOOLBAR_CALLBACK": lambda r: DEBUG and ENVIRONMENT == "development",
}

Logs for Debugging

View Logs

# All services
docker compose logs -f

# Specific service
docker compose logs -f app

# Last 100 lines
docker compose logs --tail=100 app

Structured JSON Logs

QFieldCloud outputs JSON logs. To view them formatted:
docker compose logs app -f --no-log-prefix | jq .

Nginx Logs

For detailed nginx logs:
QFC_JQ='[.ts, .ip, (.method + " " + (.status|tostring) + " " + (.resp_time|tostring) + "s"), .uri, "I " + (.request_length|tostring) + " O " + (.resp_body_size|tostring)] | @tsv'
docker compose logs nginx -f --no-log-prefix | grep ':"nginx"' | jq -r $QFC_JQ

Next Steps

Build docs developers (and LLMs) love