Input and Output Never Stop Loading

Describe the problem/error/question

I am having an issue with my self-hosted instance: the Input and Output screens never stop the ‘loading data’ animation, but it looks like the process has completed, as I can see ‘1 item’ listed at the top. I took the workflow and threw it onto our cloud-hosted instance, and it worked just fine. This used to work a few weeks ago, but we did just move this from an NPM install to a Docker setup, so maybe I am missing a setting?

What is the error message (if any)?

There is no error message; it just never stops loading. But, in Chrome Dev Tools, I do see a consistent CORS error… “has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.”

Please share your workflow

Share the output returned by the last node

N/A

Information on your n8n setup

  • n8n version: 2.18.5
  • Database (default: SQLite): Postgres
  • n8n EXECUTIONS_PROCESS setting (default: own, main): default
  • Running n8n via (Docker, npm, n8n cloud, desktop app): Docker
  • Operating system: Ubuntu Server 24.04

Welcome @Michael_Boutin since that your workflow works in n8n cloud and not inyour self-hosted docker setup and you are receiving a CORS error, I’d suspect you are facing a mixture of wrongly set up env variables and your reverse proxy, nginx/Apache etc is preventing real time connections.

I’m actually bypassing the proxy that I use for external access and accessing it directly from within the network. I think it may have something to do with Docker, but I just can’t seem to find what it could be.

The CORS error is the root cause, and since you’re bypassing the proxy and accessing directly, it’s almost certainly a missing N8N_EDITOR_BASE_URL env var in your Docker setup.

Here’s what’s happening: n8n uses Server-Sent Events (SSE) to stream execution data back to the editor in real time. The SSE endpoint URL is built from N8N_EDITOR_BASE_URL. If that env var isn’t set (or doesn’t match the URL you’re using in the browser), the browser will try to connect to the wrong origin and get blocked by CORS.

In your docker-compose.yml (or Docker run command), make sure you have:

yaml
environment:
  - N8N_EDITOR_BASE_URL=http://YOUR_SERVER_IP:5678
  - WEBHOOK_URL=http://YOUR_SERVER_IP:5678
  - N8N_HOST=0.0.0.0
  - N8N_PORT=5678
  - N8N_PROTOCOL=http
```

The value of `N8N_EDITOR_BASE_URL` must **exactly** match what you're typing in the browser address bar — including protocol (`http` vs `https`), IP/hostname, and port.

After updating, restart the container and try again. That should stop the CORS errors and let the execution output panel load properly.

Hey ZapPro! Thanks for chiming in! I do have those settings set, along with others, in the yaml file and still no luck. The CORS messages did go away with the addition of the CORS allow setting, but the input/output still just spins. I tried changing the base_url to both my internal and external address and tried it from both addresses and still no luck. This all just started when I moved to docker. I just took my environment variables from my npm install and added them here. Is there maybe something else in my yaml that may be causing this?

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    container_name: 'n8n'
    restart: always
    ports:
      - '0.0.0.0:5678:5678'
    environment:
      #N8N_BINARY_DATA_STORAGE_PATH: ''
      N8N_DEFAULT_BINARY_DATA_MODE: 'database'
      #DB_TYPE: 'sqlite'
      #DB_SQLITE_POOL_SIZE: 4
      #DB_SQLITE_VACUUM_ON_STARTUP: true
      DB_TYPE: 'postgresdb'
      DB_POSTGRESDB_HOST: '*****'
      DB_POSTGRESDB_PORT: 5432
      DB_POSTGRESDB_DATABASE: '*****'
      DB_POSTGRESDB_USER: '*****'
      DB_POSTGRESDB_PASSWORD: '*****'
      DB_PING_INTERVAL_SECONDS: 5
      N8N_EDITOR_BASE_URL: 'https://*****.net'
      N8N_TEMPLATES_ENABLED: false
      N8N_HOST: 'https://*****.net'
      N8N_PORT: 5678
      N8N_LISTEN_ADDRESS: '0.0.0.0'
      N8N_PROTOCOL: 'http'
      N8N_PERSONALIZATION_ENABLED: false
      N8N_VERSION_NOTIFICATIONS_ENABLED: true
      N8N_DIAGNOSTICS_ENABLED: true
      N8N_HIRING_BANNER_ENABLED: false
      N8N_PUBLIC_API_DISABLED: false
      N8N_REINSTALL_MISSING_PACKAGES: true
      N8N_ENABLE_MODULES: 'data-table'
      N8N_PAYLOAD_SIZE_MAX: 16
      N8N_FORMDATA_FILE_SIZE_MAX: 200
      WEBHOOK_URL: 'https://*****.net'
      EXECUTIONS_MODE: 'regular'
      EXECUTIONS_DATA_SAVE_ON_ERROR: 'all'
      EXECUTIONS_DATA_SAVE_ON_SUCCESS: 'all'
      EXECUTIONS_DATA_SAVE_ON_PROGRESS: false
      EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS: false
      EXECUTIONS_DATA_PRUNE: true
      EXECUTIONS_DATA_MAX_AGE: 240
      EXECUTIONS_DATA_PRUNE_MAX_COUNT: 500
      EXECUTIONS_DATA_HARD_DELETE_BUFFER: 1
      EXECUTIONS_DATA_PRUNE_HARD_DELETE_INTERVAL: 60
      EXECUTIONS_DATA_PRUNE_SOFT_DELETE_INTERVAL: 60
      N8N_CONCURRENCY_PRODUCTION_LIMIT: -1
      N8N_LOG_LEVEL: 'info'
      N8N_LOG_OUTPUT: 'file'
      N8N_LOG_FORMAT: 'json'
      N8N_LOG_FILE_COUNT_MAX: 14
      N8N_LOG_FILE_SIZE_MAX: 20
      N8N_PYTHON_ENABLED: true
      NODE_FUNCTION_ALLOW_BUILTIN: '*'
      NODE_FUNCTION_ALLOW_EXTERNAL: '*'
      N8N_SECURE_COOKIE: false
      N8N_RUNNERS_ENABLED: true
      N8N_RUNNERS_MODE: 'internal'
      N8N_RUNNERS_MAX_CONCURRENCY: 5
      GENERIC_TIMEZONE: 'America/New_York'
      N8N_DEFAULT_LOCALE: 'en'
      N8N_ONBOARDING_FLOW_DISABLED: true
      N8N_WORKFLOW_CALLER_POLICY_DEFAULT_OPTION: 'any'
      WORKFLOWS_DEFAULT_NAME: 'Workflow'
      N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE: true
      N8N_UNVERIFIED_PACKAGES_ENABLED: true
      N8N_COMMUNITY_PACKAGES_VERIFY: false
      N8N_DEFAULT_CORS: true
      N8N_CORS_ALLOW_ORIGIN: '*'
      N8N_TRUST_PROXY: true
    volumes:
      - ./n8n-data:/home/node/.n8n
      - ./n8n-files:/files

The really odd part is that the UI thinks the workflow is still running, which is why I think it still shows as loading. It only happens on this docker install. The npm and cloud instances both show no running timer after they are done.

Hey Michael! The “still running” UI behavior actually confirms the diagnosis — that’s exactly what happens when the SSE (Server-Sent Events) stream can’t connect properly. n8n uses SSE to push real-time execution data to the browser, so if it can’t reach the stream, the UI just hangs showing the spinner forever even though the workflow finished.

Looking at your yaml, I spotted the issue:


N8N_HOST: 'https://yoursite.net'   ← includes the protocol prefix
N8N_PROTOCOL: 'http'               ← conflicts with above, and wrong
```

`N8N_HOST` should be **just the hostname** with no `https://` prefix. The protocol goes in `N8N_PROTOCOL` separately. When they conflict, n8n builds a malformed internal URL and the SSE endpoint breaks.

Fix:
```yaml
N8N_HOST: 'yoursite.net'
N8N_PROTOCOL: 'https'
N8N_EDITOR_BASE_URL: 'https://yoursite.net/'
WEBHOOK_URL: 'https://yoursite.net/'
```

This is super common when migrating from npm — the env vars work differently there. Restart the container after and the spinning should stop. Let me know!

I set the host to just my domain (no https://) and changed the protocol to https. I originally had this at http as it performed better through Caddy if I didn’t pass through the cert. After both changes and a reset, it is still doing the same thing, whether I come at it from outside or inside the firewall/proxy. I’d love to get this working as I would prefer to use docker but, I might have to go back to the npm install, but that was having trouble upgrading which made me move to docker.

I’m willing to try anything at this point… got any other ideas?

Ah, Caddy changes things! The spinning is almost certainly Caddy buffering the SSE stream — it’s a known gotcha with n8n + Caddy.

Caddy buffers responses by default, which breaks Server-Sent Events entirely. The fix is adding flush_interval -1 to your Caddyfile’s reverse_proxy block:


yoursite.net {
    reverse_proxy n8n:5678 {
        flush_interval -1
    }
}
```

That tells Caddy to stream responses immediately instead of buffering them.

Also, since Caddy is handling HTTPS termination, your n8n env vars should be:
```yaml
N8N_HOST: '0.0.0.0'
N8N_PORT: 5678
N8N_PROTOCOL: 'http'          # Caddy handles https, n8n stays http internally
N8N_EDITOR_BASE_URL: 'https://yoursite.net/'
WEBHOOK_URL: 'https://yoursite.net/'
N8N_TRUST_PROXY: true         # you already have this ✅
```

The `flush_interval -1` is the one almost everyone misses with Caddy. Give that a shot!

ZapPrro, thanks for the new option. Unfortunately, I already had the flush statement in the caddy setup but I did try changing the host to 0.0.0.0. The issue still persists after that change. It definitely has something to do with Docker. I installed n8n via npm again last night and everything worked just fine. I tried a brand new Docker install and the same issue from the start. I’m going to keep digging. If you have any other ideas, let me know. At this point, I just want to figure it out :slight_smile:

Well… I updated to 2.19.2 and it works now. No changes to the original config. I may try going backward and see if it fixes it as well. May just be an issue with that version.

Nice find, Michael! Version-specific bug makes sense — SSE issues showing up only in Docker + a specific n8n version is a known pattern when there are changes to the runner or execution streaming internals. Good to have it documented here for anyone else on 2.18.5 hitting this. Glad 2.19.2 sorted it out!