License Activation Failure on Self-Hosted n8n

Describe the problem/error/question

I am having trouble activating my Registered Community license on a self-hosted instance. When attempting to activate via the web UI or using the environment variable, the activation fails with a validation error regarding the device fingerprint.

However, running the CLI tool inside the container shows that a valid fingerprint is being generated. There seems to be a discrepancy where the background web process/SDK is passing an empty or truncated fingerprint string to your licensing servers.

When I first access the terminal of the container and manually run n8n license:info, a full, valid 64-character fingerprint is successfully generated and visible:

\~ $ n8n license:info
Puppeteer node: Container detected via .dockerenv file
\[license SDK\] Skipping renewal on init: license cert is not initialized
## CONSUMER CONFIG ##
tenantId: 1
productIdentifier: n8n-2.26.7
deviceFingerprint: a11f905a58a7525ef325c7a4a4fc27d1bde9a2ef695a19d4264672a3bbc62997
autoRenewalEnabled: true
autoRenewalOffset: 259200 (= 72h 0m 0s)
--
## LICENSE CERT ##
version: <n/a>
tenantId: <n/a> (!)
consumerId: <n/a>
deviceFingerprint: <n/a> (!)
createdAt: <n/a>
issuedAt: <n/a>
expiresAt: <n/a>
terminatesAt: <n/a>
isEphemeral: <n/a>
isValid: false (!)
isRenewalDue: false
detachedEntitlementsCount: <n/a>
entitlements: 0

History

  1. I was unable to get Debug in Editor to work - it said I needed to be registered. I already should have been. I have been in the past - no idea why this changed.

  2. I saw this in my logs:
    [license SDK] cert is invalid because it has expired: (autorenewalsEnabled: true, expiredAt: Sat May 09 2026 15:29:44 GMT-0400 (Eastern Daylight Time), issuedAt: Wed Apr 29 2026 15:29:44 GMT-0400 (Eastern Daylight Time))

  3. I do have TZ=America/New_York and a 32 bit N8N_ENCRYPTION_KEY which hasn’t changed. The encryption key is both in the environment and in the .n8n/config file

  4. I ran this and saw:

\~ $ n8n license:info
Puppeteer node: Container detected via .dockerenv file
[license SDK] attempting license renewal
[license SDK] license successfully renewed
## CONSUMER CONFIG ##
tenantId: 1
productIdentifier: n8n-2.26.7
deviceFingerprint: a11f905a58a7525ef325c7a4a4fc27d1bde9a2ef695a19d4264672a3bbc62997
autoRenewalEnabled: true
autoRenewalOffset: 259200 (= 72h 0m 0s)
--
## LICENSE CERT ##
version: 2
tenantId: 1
consumerId: 84ac80cc-574f-4841-b0f3-2df3c875080f
deviceFingerprint: a11f905a58a7525ef325c7a4a4fc27d1bde9a2ef695a19d4264672a3bbc62997
createdAt: Fri May 09 2025 18:15:12 GMT-0400 (Eastern Daylight Time)
issuedAt: Thu Jun 18 2026 15:51:04 GMT-0400 (Eastern Daylight Time)
expiresAt: Sun Jun 28 2026 15:51:04 GMT-0400 (Eastern Daylight Time)
terminatesAt: Tue May 03 2050 18:15:12 GMT-0400 (Eastern Daylight Time)
isEphemeral: false
isValid: true
isRenewalDue: false
detachedEntitlementsCount: 0
entitlements: 1
--

## ENTITLEMENT 1 ##
id: 7a862864-5aab-4dac-a6fe-e1ea891a6459
productId: 031ebde1-0ebe-47b8-802a-29c084a2a4c3
validFrom: Fri May 09 2025 18:15:12 GMT-0400 (Eastern Daylight Time)
validTo: Sat May 05 2040 18:15:12 GMT-0400 (Eastern Daylight Time)
features: {"planName":"Registered Community","feat:folders":true,"feat:debugInEditor":true,"feat:workflowHistory":true,"feat:insights:viewSummary":true,"feat:workflowHistoryPrune":true,"quota:workflowHistoryPrune":24,"feat:advancedExecutionFilters":true,"quota:evaluations:maxWorkflows":1,"quota:insights:retention:maxAgeDays":180,"quota:insights:retention:pruneIntervalDays":24}
featureOverrides: {}
  1. When I try to click the button in the activation email or paste it in I get the same thing:
UI:
Activation key is in the wrong format

log:
[license SDK] license activation failed: request/body/deviceFingerprint must NOT have fewer than 32 characters
  1. I did n8n license:clear and then restarted. Now I get this in the log:
    [license SDK] Skipping renewal on init: license cert is not initialized

and this is what I get in the shell

\~ $ n8n license:info
Puppeteer node: Container detected via .dockerenv file
\[license SDK\] Skipping renewal on init: license cert is not initialized
## CONSUMER CONFIG ##
tenantId: 1
productIdentifier: n8n-2.26.7
deviceFingerprint: a11f905a58a7525ef325c7a4a4fc27d1bde9a2ef695a19d4264672a3bbc62997
autoRenewalEnabled: true
autoRenewalOffset: 259200 (= 72h 0m 0s)
--
## LICENSE CERT ##
version: <n/a>
tenantId: <n/a> (!)
consumerId: <n/a>
deviceFingerprint: <n/a> (!)
createdAt: <n/a>
issuedAt: <n/a>
expiresAt: <n/a>
terminatesAt: <n/a>
isEphemeral: <n/a>
isValid: false (!)
isRenewalDue: false
detachedEntitlementsCount: <n/a>
entitlements: 0
  1. I have tried using the lan ip instead of cloudflare url - http://192.168.200.12:5678/settings/usage?key=03329154-96a6-4bac-89f0-xxxxxxxxxxxx . Gives me the same errors

  2. This used to work fine on this docker image (previous builds months ago).

  3. I have also attempted passing the key directly to the container via N8N_LICENSE_ACTIVATION_KEY, which resulted in the same log failure.

I have used 3 different ai’s to help fix this and we are all out of ideas :slight_smile:

what can i do?

What is the error message (if any)?

When trying to activate via the UI or using N8N_LICENSE_ACTIVATION_KEY, the container logs show:
[license SDK] Skipping renewal on init: license cert is not initialized
[license SDK] license activation failed: request/body/deviceFingerprint must NOT have fewer than 32 characters
Could not activate license

Information on your n8n setup

  • n8n version: 2.26.7 (also happens with earlier versions)
  • Database (default: SQLite): Postgres
  • n8n EXECUTIONS_PROCESS setting (default: own, main):
  • Running n8n via (Docker, npm, n8n cloud, desktop app): synology docker
  • Operating system: synology

@jmaver your CLI run already renewed it, the second license:info shows isValid true now (expires Jun 28). the license state is stored in the db, so the cert is fixed there but your running process is still holding the expired one it cached at boot. restart the n8n container, it reloads the valid cert from the db and registered + Debug in Editor come back. it lapsed because the community license has to reach license.n8n.io/v1 to renew roughly every 10 days, so make sure that outbound isnt being blocked by a proxy or firewall.

Sadly, it isn’t.

I have restarted many times. Every boot with the activation env var shows the same error, trying to add in the activate license code manually still fails, and I still can’t Debug in Editor.

@jmaver yeah this is the device-fingerprint mismatch, your cert is bound to one fingerprint but the instance is presenting a different one each boot so it keeps rejecting it no matter how many restarts, which is also why license.cert wont hold. drop the N8N_LICENSE_ACTIVATION_KEY env var first, leaving it in means every boot re-runs activation and re-hits the mismatch instead of just loading whats in the db. but since the binding itself is broken the real unblock is emailing help@n8n.io to reset the key, the community key gets consumed against the old fingerprint and only they can release it so it rebinds to your current instance.

Hi @jmaver

When you run n8n license:info in the shell, you are likely running as a user (often root or the default node user) who has full access to the system identifiers used to generate the fingerprint. However, the main n8n process—which handles the Web UI and the N8N_LICENSE_ACTIVATION_KEY—is failing to resolve that same fingerprint, sending an empty or null string to the licensing server, which then triggers the “fewer than 32 characters” validation error.

To resolve the issue, try to explicitly map a machine-id file into the container to ensure it is consistent and readable.

  1. Create a file on your Synology host (e.g., in your n8n config folder) called machine-id with a random 32-character hex string inside it.
  2. Add a volume mapping in your Docker/Container Manager settings:
    • File/Folder: /volume1/docker/n8n/machine-id (adjust to your path) →Mount path: /etc/machine-id
  3. Restart the container.

Does that help?

no, that didn’t seem to make any difference. I see it on /etc in the container, but nothing about it in the logs and the same activation failure

Run the following command in the container shell

ls -l /etc/machine-id /var/lib/dbus/machine-id

what does it show?

/etc $ ls -al /etc/machine-id
-rwxr-xr-x 1 1024 100 32 Jun 22 11:57 /etc/machine-id
/etc $ ls -l /etc/machine-id /var/lib/dbus/machine-id
ls: /var/lib/dbus/machine-id: No such file or directory

Check your N8N_ENCRYPTION_KEY. Is it exactly 32 characters long?

Run this command in your container terminal

ps aux | grep n8n

What does it show?

/etc $ echo “${#N8N_ENCRYPTION_KEY}”
32

/etc $ ps aux | grep n8n
6 node 0:40 {MainThread} node /usr/local/bin/n8n start

The key detail here is that n8n’s fingerprint generation checks both /etc/machine-id AND /var/lib/dbus/machine-id - since that second path is missing in your container, the ID may still not resolve correctly even with the first one mapped.

Add a second volume mount to your docker-compose:

- /var/lib/dbus/machine-id:/var/lib/dbus/machine-id:ro

If you don’t have that file on the host, create it first: cat /etc/machine-id | sudo tee /var/lib/dbus/machine-id. Then restart the container and retry license activation.

@jmaver the machine-id path is a dead end, your CLI already builds a full 64-char fingerprint off /etc/machine-id so resolution works fine, thats not it. the empty fingerprint only shows in the activation request, thats the real bug, activate isnt sending the fingerprint your instance clearly computes. and your earlier license:info renewed a valid cert (isValid: true), so renewal works and only activation is broken, which means license:clear was the wrong move, it wiped that good cert and pushed you onto the broken activate path. retrying activation or the env key wont help now. easiest recovery is restoring the license.cert row in the settings table from a db snapshot taken before the clear. no snapshot, then this is a clean reproducible activation bug, send that license:info output to help@n8n.io so they re-seed it against your fingerprint.

~ $ ls -l /etc/machine-id /var/lib/dbus/machine-id
-rwxr-xr-x 1 1024 100 32 Jun 22 11:57 /etc/machine-id
-rwxr-xr-x 1 1024 100 32 Jun 22 11:57 /var/lib/dbus/machine-id

same results. here is debug version of log, no that it seems to add anything:


- 2026-06-22T19:29:18.132Z | debug | [license SDK] initializing for deviceFingerprint n8n-j {"scopes":["license"],"file":"LicenseManager.js","function":"log"}

- 2026-06-22T19:29:18.137Z | info | [license SDK] Skipping renewal on init: license cert is not initialized {"scopes":["license"],"file":"LicenseManager.js","function":"log"}

- 2026-06-22T19:29:18.138Z | debug | License initialized {"scopes":["license"],"file":"license.js","function":"init"}

- 2026-06-22T19:29:18.141Z | debug | Attempting license activation {"file":"base-command.js","function":"initLicense"}

- 2026-06-22T19:29:18.335Z | warn | [license SDK] license activation failed: request/body/deviceFingerprint must NOT have fewer than 32 characters {"scopes":["license"],"file":"LicenseManager.js","function":"log"}

- 2026-06-22T19:29:18.574Z | error | Could not activate license {"error":{"name":"Error","message":"license activation failed: request/body/deviceFingerprint must NOT have fewer than 32 characters","stack":"Error: license activation failed: request/body/deviceFingerprint must NOT have fewer than 32 characters\n at v.activate (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/@n8n_io+license-sdk@2.25.0/node_modules/@n8n_io/license-sdk/src/LicenseManager.ts:461:17)\n at processTicksAndRejections (node:internal/process/task_queues:104:5)\n at License.activate (/usr/local/lib/node_modules/n8n/src/license.ts:208:3)\n at Start.initLicense (/usr/local/lib/node_modules/n8n/src/commands/base-command.ts:318:5)\n at Start.init (/usr/local/lib/node_modules/n8n/src/commands/start.ts:239:3)\n at CommandRegistry.execute (/usr/local/lib/node_modules/n8n/src/command-registry.ts:82:4)\n at /usr/local/lib/node_modules/n8n/bin/n8n:63:2"},"file":"base-command.js","function":"initLicense"}

@jmaver right, both files are there now and it still fails, so machine-id is fully ruled out. but look at that debug line, the server inits with deviceFingerprint “n8n-j…” which is short, thats the under-32-char value getting rejected, not the 64-char hash your CLI builds. so the running process is being handed a truncated fingerprint from somewhere instead of computing it. whats the containers hostname, and are there any leftover N8N_LICENSE_* or fingerprint-related entries in your compose/config from the earlier attempts? that short n8n-j string is almost certainly coming from one of those.

Run this in your terminal

su - node -c "n8n license:info"

What does it show?

sudo docker exec -it n8n n8n license:info

## CONSUMER CONFIG ##
tenantId: 1
productIdentifier: n8n-2.26.7
deviceFingerprint: a11f905a58a7525ef325c7a4a4fc27d1bde9a2ef695a19d4264672a3bbc62997
autoRenewalEnabled: true
autoRenewalOffset: 259200 (= 72h 0m 0s)
--
## LICENSE CERT ##
version: <n/a>
tenantId: <n/a> (!)
consumerId: <n/a>
deviceFingerprint: <n/a> (!)
createdAt: <n/a>
issuedAt: <n/a>
expiresAt: <n/a>
terminatesAt: <n/a>
isEphemeral: <n/a>
isValid: false (!)
isRenewalDue: false
detachedEntitlementsCount: <n/a>
entitlements: 0

Here is my compose:

name: n8n
services:
n8n:
image: n8n-with-puppeteer:${N8N_VERSION}
build:
context: git@gitea:jmaver/docker-stacks.git#main
dockerfile: stacks/n8n/setup/n8n-with-puppeteer-dockerfile
args:
N8N_VERSION: "${N8N_VERSION}"

container_name: n8n

volumes:
- /volume1/docker/n8n/data:/home/node/.n8n
- /volume1/docker/n8n/machine-id:/etc/machine-id
- /volume1/docker/n8n/machine-id:/var/lib/dbus/machine-id:ro

environment:
# Public URLs / base config
DOMAIN_NAME: [xxxx.com](http://xxxx.com)
SUBDOMAIN: n8n-j
N8N_HOST: [n8n-j.xxxx.com](http://n8n-j.xxxx.com)
N8N_PORT: 5678
N8N_PROTOCOL: http
N8N_EDITOR_BASE_URL: [https://n8n-j.xxxx.com/](https://n8n-j.xxxx.com/)
WEBHOOK_URL: [https://n8n-j.xxxx.com/](https://n8n-j.xxxx.com/)
GENERIC_TIMEZONE: America/New_York
TZ: America/New_York
PGID: 100
PUID: 1030

# Core behavior
N8N_INSTANCE_ID: n8n-j
N8N_LOG_LEVEL: debug
N8N_PROXY_HOPS: 1
N8N_SECURE_COOKIE: false
N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS: true
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY:?set in env}
N8N_LICENSE_ACTIVATION_KEY: ${N8N_LICENSE_ACTIVATION_KEY:?set in env}
N8N_LICENSE_AUTO_RENEW_ENABLED: true
N8N_PAYLOAD_SIZE_MAX: 64

#fix missing packages
N8N_REINSTALL_MISSING_PACKAGES: "true"

# Allow Code nodes to access env vars (your preference)
N8N_BLOCK_ENV_ACCESS_IN_NODE: "false"

# Queue mode off
EXECUTIONS_MODE: regular
N8N_CONCURRENCY_PRODUCTION_LIMIT: 5

# External task runners (broker lives here)
N8N_RUNNERS_MODE: external
N8N_RUNNERS_BROKER_LISTEN_ADDRESS: 0.0.0.0
N8N_RUNNERS_AUTH_TOKEN: ${N8N_RUNNERS_AUTH_TOKEN:?set in env}
N8N_RUNNERS_TASK_REQUEST_TIMEOUT: 300
N8N_NATIVE_PYTHON_RUNNER: "false"
N8N_NATIVE_JAVASCRIPT_RUNNER: "false"

# Telemetry / diagnostics
N8N_DIAGNOSTICS_ENABLED: "false"
N8N_DIAGNOSTICS_ENABLE_HEALTHCHECK: "false"
N8N_VERSION_NOTIFICATIONS_ENABLED: "false"
N8N_TEMPLATES_ENABLED: "false"
EXTERNAL_FRONTEND_HOOKS_URLS: ""
N8N_DIAGNOSTICS_CONFIG_FRONTEND: ""
N8N_DIAGNOSTICS_CONFIG_BACKEND: ""
N8N_ONBOARDING_FLOW_DISABLED: "true"

# Database
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: xxxx
DB_POSTGRESDB_PORT: 5432
DB_POSTGRESDB_DATABASE: ${POSTGRES_DB:?set in env}
DB_POSTGRESDB_USER: ${POSTGRES_USER:?set in env}
DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD:?set in env}

# Puppeteer / Chromium
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: "true"
PUPPETEER_EXECUTABLE_PATH: /usr/bin/chromium

ports:
- '5678:5678'
networks:
- infra

command: [ "start" ]

restart: unless-stopped

healthcheck:
test: [ "CMD-SHELL", "wget -q --spider [http://127.0.0.1:5678/healthz](http://127.0.0.1:5678/healthz) || exit 1" ]
interval: 60s
timeout: 5s
retries: 5
start_period: 60s

cap_add:
- SYS_ADMIN

cpu_shares: 1800
mem_limit: 4g
shm_size: 3gb

security_opt:
- seccomp:unconfined

correction to my last reply, i had the mechanism wrong so ignore the hostname bit. n8ns license fingerprint is the instanceId (from the source, deviceFingerprint: () => instanceId), not the hostname. your CLI shows a valid 64-char instanceId (a11f905a…), but the activation request is getting rejected for sending one under 32 chars, so the activate path isnt picking up a valid instanceId even though one clearly exists.

i dont have a verified root cause for why it only comes up short in the activate flow. but since your earlier license:info already renewed a valid cert, the most reliable path is restoring that license.cert row from a db snapshot taken before you ran license:clear, or having n8n support re-seed it, rather than more machine-id or hostname changes.

ok, thank you - I will email them

Hey @jmaver, spotted it in your compose, you have:

N8N_INSTANCE_ID: n8n-j

That’s only 5 characters. n8n’s license SDK derives the deviceFingerprint directly from the instance ID, and the licensing server requires a minimum of 32 characters. So n8n-j is what’s being sent as the fingerprint, which is exactly why you’re getting the “must NOT have fewer than 32 characters” error.

Fix: Either remove N8N_INSTANCE_ID entirely (n8n will auto-generate a valid UUID), or replace it with a proper UUID:

N8N_INSTANCE_ID: n8n-j-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

After changing it, remove N8N_LICENSE_ACTIVATION_KEY temporarily, restart, run n8n license:info to confirm the new fingerprint is 64 chars, then re-add the activation key and restart once more.

This should resolve it without needing to contact support.