Statuses and errors
There are three families of results, in the order you typically meet them: validation statuses describe the license's verdict, configuration errors mean your integration is set up wrong and should be fixed rather than retried, and transport errors mean the call itself failed.
Validation statuses
After validate_license / ValidateLicenseAsync, the result carries one status.
Native constants are SWS_LICENSE_STATUS_*; .NET uses the LicenseStatus enum.
| Native | .NET | Meaning - and what your application should do |
|---|---|---|
VALID |
Valid |
Proceed. Persist the updated license if one was issued. |
NOT_FOUND |
NotFound |
No license, and none could be acquired: no license key or vendor id is configured, or the service refused the key. The error detail says which refusal: an unknown key (license_not_found), a wrong vendor id (vendor_mismatch), an inactive vendor account (account_inactive), or a device whose hardware fingerprint is too weak to recognise again (device_unidentifiable). For an unknown key, have the customer copy it from the license email again; for a vendor mismatch, check the vendor id your app is built with; for a weak fingerprint, see hardware IDs. |
BAD_SIGNATURE |
BadSignature |
The stored license fails verification, usually because it is corrupted or was tampered with. Delete the local file and re-activate online. |
EXPIRED |
Expired |
The license is past its validity, either its stored certificate or, refused at activation, the license itself. On a license whose duration counts from each device's first activation, such as an automatic trial, it can also mean that this device's own period has ended, while other devices go on; for a trial, show your purchase page. For subscriptions this usually resolves itself at the next online validation, since renewal is a form of re-issuance; for fixed-term licenses, prompt the customer to renew or purchase. A perpetual license with a maximum offline period reports EXPIRED when the device has not reached the licensing service for the whole period, and recovers at the next validation with connectivity. |
NOT_YET_VALID |
NotYetValid |
Validity starts in the future. On a stored license this is almost always a wrong device clock: tell the customer to fix the clock, and do not disable features silently. Refused at activation, the license's own start date is in the future. |
REVOKED |
Revoked |
The license was revoked in the console, for example after a refund, a chargeback, or a leaked key. Deny the licensed functionality and direct the customer to support. A device sees the revocation at its next start with connectivity, through the revocation list; a device that stays offline stops validating when its maximum offline period ends, at the latest. A trial license is the exception: its certificates are never on the revocation list, so a running trial keeps validating until its certificate ends at the latest: the trial's own end, or sooner when the product sets a maximum offline period (revocation). |
BAD_CONTEXT |
BadContext |
The license belongs to a different device, because the hardware changed beyond the allowed tolerance or the file was copied. Offer re-activation, and deactivate the old machine first if it still exists. Refused at activation, the license activates only with a different kind of context (context_type_mismatch). |
BAD_SCOPE |
BadScope |
The license carries no scope attribute at all: a malformed or hand-assembled license file, never a normally issued one. Delete the local file and re-activate online. |
PAYMENT_REQUIRED |
PaymentRequired |
The subscription behind the license has lapsed, or your plan accepts no new devices. The status message carries the subscription state (past_due, canceled, and so on), or the plan reason (plan_limit, trial_expired). Show state-appropriate messaging: "update your payment method" for past_due calls for a different conversation than canceled. |
SEAT_LIMIT |
SeatLimit |
This is a floating license and every seat is leased. The status message carries the soonest lease expiry in seconds ("" if unknown), which is the earliest a retry can succeed. Offer "try again in a few minutes"; never retry in a tight loop. |
BAD_PRODUCT |
BadProduct |
The license belongs to a different product than the one your app declared with set_product_id() / SetProductId. Tell the customer which product the key actually matches (it's on their receipt) and where to get the right one. Reported only when your app declares a product; licenses without a stamped product pass this check. |
ACTIVATION_LIMIT |
ActivationLimit |
Since SDK 1.1.0. The license is already in use on its maximum number of devices, or its activations are used up. Point the customer at deactivating it on a machine they no longer use, or at buying another seat. |
UNAVAILABLE |
Unavailable |
Since SDK 1.1.0. A first activation could not be completed: the licensing service could not be reached or gave no usable answer (network, DNS, TLS, proxy, timeout, a server fault, throttling). Ask the customer to check the connection and try again later. Do not ask for a new key. One kind of throttling is specific to trials: a product trial's daily limit on new machines (new_device_limit), which lifts at midnight UTC. |
The forward-compatibility rule: future SDK and service versions may add new statuses. Treat an unknown status as invalid, never as probably fine.
Why an activation failed
Since SDK 1.1.0, when the online activation (or renewal) of a validation call fails, the
result also says why: .NET result.Error (an ActivationError: HttpStatus, Code,
Message, Exception; ToString() gives one line), native get_error_http_status(),
get_error_code() and get_error_message(). Log it whenever validation is not valid.
It is the difference between "the key is unknown" and "the network is down", and it is
what support asks for first.
| Code | Meaning |
|---|---|
license_not_found |
No license has this key (HTTP 401). |
vendor_mismatch |
The vendor id is missing or belongs to a different vendor than the key (HTTP 401). |
account_inactive |
The vendor account that owns the license is suspended (HTTP 401). |
license_revoked, license_expired, license_not_yet_valid |
The license itself refuses activation (HTTP 403). license_expired also refuses a device whose own period ended, on a license whose duration counts from each device's first activation, such as a trial; its expired_at field gives the moment the license, or that device's period, ended. |
context_limit, activation_limit, context_activation_limit, seat_limit |
No seat or activation is left (HTTP 403). |
wrong_product, context_type_mismatch, invalid_scope, condition_failed, invalid_request |
The request does not fit the license, or is malformed (HTTP 403 / 400). |
device_unidentifiable |
This device's hardware fingerprint is too weak to recognise it again (HTTP 403). The SDK reports NOT_FOUND. See hardware IDs. |
vm_not_allowed |
A license that does not allow virtual machines (Allow virtual machines unticked in its terms, on the product or on the license) refused a new device that reported running in one (HTTP 403, NOT_FOUND). Devices already activated are never refused. Only SDK 1.2.0 and later report virtual machines. See virtual machines. |
payment_required |
A lapsed subscription, or the vendor's plan (HTTP 402). |
rate_limited, renewal_too_early |
Throttled; retry after the indicated time (HTTP 429). Since SDK 1.2.0, a first activation refused with renewal_too_early, which happens when the application was reinstalled or lost its stored license while this machine's license is still fresh, releases this machine's seat and activates once more by itself. |
new_device_limit |
A product trial's daily limit on new machines is reached (HTTP 429). SDK 1.1.0 reports UNAVAILABLE. Retry after the next midnight UTC; renewals and returning devices are never capped. |
network, timeout |
No answer at all (HTTP status 0): connection, DNS, TLS, proxy, or a timeout. |
bad_response |
The service answered with success but without a usable certificate. |
client_error |
A local failure before or while sending the request. |
SDK 1.0.0 reports every failed first activation as NotFound, including a request that
never left the machine, and does not keep the reason. If you are on 1.0.0 and see
NotFound for a key you know is right, upgrade to see the cause.
Transport errors
| Native | Meaning |
|---|---|
SWS_OK |
Success. |
SWS_EFAIL |
Unknown/unclassified failure. |
SWS_ENOTIMPL |
Not implemented. |
SWS_EINVAL |
Invalid argument, including an offline-activation import whose reply does not match the pending file. |
SWS_ENOMEM |
Out of memory. |
SWS_EAUTH |
Authentication failed at the service. |
In .NET these surface as exceptions: SwsException (the base class),
SwsArgumentException for an invalid argument, and SwsServerException when the
service rejected the call. Cancelling ValidateLicenseAsync through its cancellation
token throws OperationCanceledException (since SDK 1.1.0). Network unreachability during a renewal attempt is not
fatal while the stored license is still valid, because the SDK validates locally.
Design your UX so that a temporarily offline machine with a valid license never nags
the customer.
Troubleshooting matrix
| Symptom | Likely cause | Fix |
|---|---|---|
Worked yesterday, BAD_CONTEXT today |
Hardware change beyond fingerprint tolerance, or copied license file | Re-activate; deactivate the old machine if reachable |
EXPIRED on a healthy subscription |
Machine offline past the renewal window | Get online once; validation renews automatically |
NOT_YET_VALID |
Device clock set in the past | Fix the clock |
SEAT_LIMIT with a retry hint |
All floating seats leased | Wait out the hint; ensure clients deactivate on exit |
NOT_FOUND for a key you minted moments ago |
Key mistyped, or wrong vendor id: the error code says which | Copy the key from the license email again (SDK 1.1.0 fixes case, spaces and dashes for you); check the vendor id |
NOT_FOUND in a .NET app published trimmed or Native AOT, on SDK 1.0.0 |
SDK 1.0.0 cannot build its request in such an app, so nothing is sent | Upgrade to SDK 1.1.0, or see Publishing your app |
UNAVAILABLE |
No answer from the service: offline, a proxy or firewall, or a service fault | Check the connection; see proxies and private CAs; retry later |
UNAVAILABLE with new_device_limit on a first run |
The product trial's daily limit on new machines is used up | The machine can start its trial after midnight UTC; ask the customer to try again then |
NOT_FOUND with device_unidentifiable |
The device cannot be identified reliably enough to recognise it again, typically a .NET Native AOT app built with SDK 1.1.0, on some Windows machines | Upgrade to SDK 1.2.0 or later, or publish without Native AOT; see hardware IDs |
ACTIVATION_LIMIT |
Every seat or activation of the license is used | Deactivate an old machine, or buy another seat |
BAD_PRODUCT on a key you sold |
The key belongs to a different product than the app declared (set_product_id) |
The customer bought product A and is running product B. Point them at the right download or the right key |
Still stuck? Write to support@softactivate.com with
the status, the SDK version, and (for activation problems) your vendor id, the
activation error line and roughly when it happened - never
send license private keys or license.pending files.