Skip to content

Commit 088d31c

Browse files
committed
docs(license-server): add troubleshooting page for license check failures
New page listing canonical License Server client errors (INVALID_LICENSE_SECRET 101, INVALID_LICENSE_CHECK_SECRET 107, CONNECTION_ERROR 400, PKIX SSL trust failure, GENERAL_ERROR) with diagnostic steps and per-code recovery instructions. Documents the new ERROR banner format, container exit code semantics, and the docker-compose restart: on-failure recommendation that avoids the infinite restart loop on unresolved license errors. Linked from the prerequisites section of what-is-license-server.mdx where the "may shut down" behavior was previously only vaguely mentioned. Added a Troubleshooting group to the License Server sidebar.
1 parent f119f24 commit 088d31c

3 files changed

Lines changed: 143 additions & 0 deletions

File tree

astro.sidebar.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4015,6 +4015,11 @@ export const licenseSidebar: SidebarConfig = [
40154015
translations: { uk: 'Акаунт та оплата' },
40164016
items: ['docs/license-server/billing-info', 'docs/license-server/user'],
40174017
},
4018+
{
4019+
label: 'Troubleshooting',
4020+
translations: { uk: 'Усунення несправностей' },
4021+
items: ['docs/license-server/troubleshooting'],
4022+
},
40184023
];
40194024

40204025
/** Maps tab group label → URL to navigate when the tab is clicked (optional per-group). */
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
---
2+
title: Troubleshooting license check failures
3+
description: Common License Server client errors, what each code means, and how to recover.
4+
---
5+
6+
import { Aside } from '@astrojs/starlight/components';
7+
8+
When the License Server client cannot validate a license, the ThingsBoard PE node logs a single banner on **ERROR** level and exits the JVM:
9+
10+
```text
11+
ERROR ... BasicSubscriptionService : *** LICENSE CHECK FAILED ({CODE} - code {N}) - shutting down with exit code [{N}]. See https://thingsboard.io/docs/license-server/what-is-license-server/ ***
12+
```
13+
14+
To find every failure across collected logs, grep for the marker:
15+
16+
```bash
17+
grep "LICENSE CHECK FAILED" tb.log
18+
```
19+
20+
## Common error codes
21+
22+
| Code | Name | What it means |
23+
|------|------|----------------|
24+
| 101 | INVALID_LICENSE_SECRET | The value of `TB_LICENSE_SECRET` does not match any active subscription on the License Server. |
25+
| 107 | INVALID_LICENSE_CHECK_SECRET | The per-check secret was rejected; the local instance data file is stale, corrupted, or shared between nodes that should each activate separately. |
26+
| 400 | CONNECTION_ERROR | The client cannot reach `license.thingsboard.io` over HTTPS. |
27+
|| PKIX / SSL trust failure | TLS handshake to the License Server fails because the JVM truststore does not include the corporate proxy root CA. Usually surfaces inside a CONNECTION_ERROR (400) stack trace. |
28+
|| GENERAL_ERROR | Empty `TB_LICENSE_SECRET`, or an unexpected error during activation or check. The root cause is in the stack trace above the banner. |
29+
30+
## How to recover
31+
32+
### INVALID_LICENSE_SECRET (101)
33+
34+
**Cause.** The License Server received a license secret it does not recognize:
35+
- The value was copied incorrectly (stray quotes, trailing whitespace, partial selection, etc.).
36+
- The secret belongs to a different installation and was reused here.
37+
- The subscription was cancelled or expired.
38+
39+
**Fix.**
40+
1. Open your [License Portal](https://license.thingsboard.io/) and copy the license secret exactly as shown.
41+
2. Set `TB_LICENSE_SECRET` in your environment (Docker, systemd, Kubernetes Secret, etc.).
42+
3. Restart the ThingsBoard PE node.
43+
44+
### INVALID_LICENSE_CHECK_SECRET (107)
45+
46+
**Cause.** Activation produced a per-instance file (`instance-license-{TB_SERVICE_ID}.data` by default in MSA setups, `instance-license.data` in standalone) that the License Server no longer accepts:
47+
- The file was deleted or replaced.
48+
- The same file was copied across nodes that should each activate independently.
49+
- The file was restored from a backup of a different installation.
50+
51+
**Fix.**
52+
1. Stop the ThingsBoard PE node.
53+
2. Delete the stale instance data file. Keep the original `TB_LICENSE_SECRET` value.
54+
3. Restart the node. The client re-activates against the License Server and writes a new instance data file.
55+
56+
<Aside type="caution">
57+
In clustered MSA deployments, each node activates independently and writes its own `instance-license-{TB_SERVICE_ID}.data` file. Do not share the data folder between nodes or copy this file when scaling out.
58+
</Aside>
59+
60+
### CONNECTION_ERROR (400)
61+
62+
**Cause.** The License Server client cannot reach `license.thingsboard.io`:
63+
- The host is blocked by a corporate firewall.
64+
- Outbound HTTPS (port 443) is restricted on the ThingsBoard node.
65+
- An HTTP proxy is required and is not configured for the JVM.
66+
67+
**Fix.**
68+
1. From the ThingsBoard host, confirm reachability:
69+
```bash
70+
curl -v https://license.thingsboard.io/
71+
```
72+
2. Allow outbound HTTPS to `license.thingsboard.io` in your firewall rules.
73+
3. If an HTTP proxy is required, set `HTTPS_PROXY` and `HTTP_PROXY` in the node environment, or pass the equivalent JVM properties:
74+
```bash
75+
JAVA_OPTS="-Dhttps.proxyHost=proxy.example.com -Dhttps.proxyPort=8080"
76+
```
77+
78+
### PKIX / SSL trust failure
79+
80+
**Cause.** A corporate TLS-inspection proxy intercepts the HTTPS connection and presents a certificate that the JVM truststore does not include. The exception in the stack trace reads `PKIX path building failed` or similar.
81+
82+
**Fix.**
83+
1. Obtain the root CA certificate of your corporate proxy from your IT team.
84+
2. Import it into a custom truststore:
85+
```bash
86+
keytool -importcert -alias corp-proxy -file corp-proxy-root.cer \
87+
-keystore /etc/ssl/tb-cacerts -storepass changeit
88+
```
89+
3. Point the JVM at the custom truststore via `JAVA_OPTS`:
90+
```bash
91+
JAVA_OPTS="-Djavax.net.ssl.trustStore=/etc/ssl/tb-cacerts -Djavax.net.ssl.trustStorePassword=changeit"
92+
```
93+
4. Restart the ThingsBoard PE node.
94+
95+
<Aside type="tip">
96+
Prefer a custom truststore over modifying the JVM default `cacerts`. The default file is overwritten on JDK upgrades and ties your trust chain to a specific JDK build.
97+
</Aside>
98+
99+
### GENERAL_ERROR
100+
101+
**Cause.** A failure that does not map to a specific License Server code:
102+
- `TB_LICENSE_SECRET` is empty or not set.
103+
- An unexpected exception during activation or check (DNS lookup, JVM cryptography misconfiguration, etc.).
104+
105+
**Fix.**
106+
1. Confirm `TB_LICENSE_SECRET` is set and non-empty in the node environment.
107+
2. Read the stack trace above the `LICENSE CHECK FAILED` banner. The `Caused by:` chain identifies the underlying error.
108+
3. If the cause is not obvious, [contact us](/contact-us/) with the full stack trace and the value of `TB_SERVICE_ID`.
109+
110+
## Container exit code and restart policy
111+
112+
When the License Server client decides to shut down, the JVM exits with a non-zero code. Check it on the failed container:
113+
114+
```bash
115+
docker inspect <tb-node-container> --format '{{.State.ExitCode}}'
116+
```
117+
118+
The banner reports the JVM exit code (the value passed to `System.exit`). On POSIX the process exit status uses the low eight bits, so a JVM exit code of `-1` surfaces as `255` in `docker inspect` and shell output. Either way the code is non-zero.
119+
120+
By default the ThingsBoard PE Docker Compose sets `restart: always`, which restarts the container regardless of exit code. With an unresolved license error this produces an infinite restart loop with no obvious crash.
121+
122+
Switch the restart policy to `on-failure` with a retry cap so a permanent license failure stops the container instead of looping:
123+
124+
```yaml
125+
services:
126+
tb-monolith:
127+
restart: on-failure:3
128+
```
129+
130+
With this policy the container restarts up to three times, then stops. The failure stays visible in `docker ps -a` and triggers monitoring alerts on container state.
131+
132+
## Where to go next
133+
134+
- [What is License Server?](/docs/license-server/what-is-license-server/) — License Server architecture and activation flow.
135+
- [Subscription plans](/docs/license-server/subscription/) — pricing and limits per plan.
136+
- Still stuck? [Contact us](/contact-us/) with the full ERROR banner and stack trace.

src/content/docs/docs/license-server/what-is-license-server.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ See [Architecture](#architecture) for more details.
8484
The License Server Client (e.g. your ThingsBoard PE instance) requires an internet connection to the host `license.thingsboard.io` to issue license check requests.
8585
In case internet connection to the host is not available for more than 24 hours, License Server Client may shut down the ThingsBoard instance.
8686

87+
If the License Server Client fails to validate the license, the ThingsBoard PE node logs a `*** LICENSE CHECK FAILED ***` banner on the ERROR level and exits with a non-zero JVM code. See [Troubleshooting license check failures](/docs/license-server/troubleshooting/) for diagnostic steps and recovery per error code.
88+
8789
## Architecture
8890

8991
The License Server provides REST API for the License Server clients to **activate** and **check** licenses.

0 commit comments

Comments
 (0)