Skip to main content

Licensing

This page describes how a Foundation4 license is bound to an installation, how operators read the system ID, apply and renew a license, and what the license limits. The page also describes how Foundation4 behaves when the license is invalid, expired or exceeded. Operators and administrators who install or run Foundation4 use this page.

The commands on this page read the production values file foundation4ai.values.yaml, created in Install on Kubernetes. An evaluation installation uses evaluation.values.yaml instead.

License binding​

Every Foundation4 installation requires a license, including an evaluation installation. The Foundation4 provider issues each license for one system ID. The system ID identifies one PostgreSQL database.

Foundation4 computes the system ID from PostgreSQL catalog object identifiers (OIDs) of the public schema, the owner of that schema and the api_keys table. PostgreSQL assigns these identifiers when the database and the Foundation4 tables are created. The system ID therefore exists only after the database migration has created the schema, and the value is a string of 64 hexadecimal characters.

EventSystem IDLicense
Pod restart, Helm upgrade, application release reinstalled against the same databaseUnchangedRemains valid
New database, including a new installationNewNew license required
Bundled PostgreSQL pod deleted or rescheduled (evaluation profile)New, because the database is recreated emptyNew license required
Logical restore with pg_dump and pg_restore, into any databaseNewNew license required
Physical restore, storage snapshot, or failover to a physical replicaExpected to be unchanged; not yet testedConfirm with the license check log
public schema assigned to a new owner, or api_keys table recreatedNewNew license required

The following rules keep the system ID stable:

  • Default schema names. database.schema keeps the default, public. The installation Jobs and the command-line tools compute the system ID from the public schema, while the API server and the workers use database.schema, so a changed schema name produces two different system IDs.
  • Schema ownership. The owner of the public schema does not change after the license is installed.

Database describes the database requirements, and Backup, restore and upgrades describes restores.

System ID retrieval​

The system ID is available from three sources:

  • License check Job log. The Job foundation4ai-api-server-license-check prints the system ID in the first line of the log, at every installation and upgrade of the application release. This source is the only one available during the first installation.
  • Command in a running pod. foundation4ai license system-id prints the system ID of the database that the pod is configured for.
  • Startup warning. When the license does not match, the API server and the workers log a warning with the system ID before exiting.

Read the system ID from the license check Job log:

kubectl logs -n foundation4ai job/foundation4ai-api-server-license-check

Expected result: the first line holds the system ID, and the second line holds the license status.

SystemID: <system ID>
Checking for a valid license... Invalid

Read the system ID from a running API server pod:

kubectl exec -n foundation4ai deploy/foundation4ai-api-server -c server -- \
./foundation4ai license system-id

Expected result: one line with 64 hexadecimal characters.

Find the startup warning in the log of an API server that exited:

kubectl logs -n foundation4ai deploy/foundation4ai-api-server -c server --previous | \
grep "Failed to validate license for system id"

Expected result: a WARN line that ends with Failed to validate license for system id: <system ID>.

License contents​

foundation4ai license details prints the contents of a license after checking the license against the system ID of the database:

kubectl exec -n foundation4ai deploy/foundation4ai-api-server -c server -- \
./foundation4ai license details '<license>'

Expected result for a license that matches the database, with each value in angle brackets replaced by the license contents:

License: <license holder> (expires on <date> <time> UTC)
System ID: <system ID>
Version: 2
Limits:
Pipelines: <limit>
Documents: <limit>

The output has the following parts:

  • Holder and expiry. The first line names the license holder and the expiry date and time in UTC, or (perpetual) for a license without an expiry date.
  • Optional lines. Description: and Environment: lines appear when the license carries these fields.
  • Limits. One line for each limited object type: Pipelines, Documents, Fragments, Text Splitters, Embedding Models, Agents, LLMs, Api Keys and Taxonomies. An object type without a line has no limit, and none means that no object type is limited.
  • Errors. A single word replaces the details when the license cannot be used: Invalid for a license that is malformed, of an unsupported version or issued for another system ID, or Expired.

License installation​

The first installation obtains the system ID, then installs the license. The steps are part of Install on Kubernetes and of steps 4 to 6 of Install for evaluation:

  1. The secrets file carries the placeholder pending in FOUNDATION4AI_APP_LICENSE.
  2. The first application install migrates the database, then stops at the license check, which prints the system ID and waits.
  3. The operator sends the system ID to the Foundation4 provider and receives the license.
  4. The operator sets the license in foundation4ai.secrets.env, applies the Secret, upgrades the core release, deletes the waiting license check Job and installs the application release again.

The license check Job waits for 365 days after reporting a failed check, so that the system ID stays readable in the log. Helm therefore stops the install at the Helm timeout, and the Job keeps running after Helm stops. The Job is deleted before the next install or upgrade of the application release.

License renewal​

A renewed license replaces the license of a running installation, for example before the expiry date or when the limits change. The renewed license is checked first, because a license that fails the check stops every restarted pod.

  1. Check the renewed license against the database:

    kubectl exec -n foundation4ai deploy/foundation4ai-api-server -c server -- \
    ./foundation4ai license details '<renewed license>'

    Expected result: the license details, starting with License:, and the expected expiry date and limits. Invalid or Expired means that the license cannot be used; the procedure stops here.

  2. Replace the value of FOUNDATION4AI_APP_LICENSE in foundation4ai.secrets.env and apply the Secret:

    kubectl kustomize . | kubectl apply -f -

    Expected result: secret/foundation4ai-secrets configured.

  3. Upgrade the core release, which copies the license into the Secret foundation4ai-core:

    helm upgrade foundation4ai-core ./charts/foundation4ai-core \
    -n foundation4ai -f foundation4ai.values.yaml --wait --timeout 10m

    Expected result: Helm reports STATUS: deployed.

  4. Upgrade the application release, which copies the license into the configuration of the pods and runs the license check:

    helm upgrade foundation4ai ./charts/foundation4ai \
    -n foundation4ai -f foundation4ai.values.yaml --wait --timeout 10m
    kubectl logs -n foundation4ai job/foundation4ai-api-server-license-check

    Expected result: Helm reports STATUS: deployed, and the license check log ends with Checking for a valid license... OK.

  5. Restart the API server and the workers, which read the license only at startup:

    kubectl rollout restart -n foundation4ai \
    deployment/foundation4ai-api-server deployment/foundation4ai-api-server-worker
    kubectl rollout status -n foundation4ai deployment/foundation4ai-api-server
    kubectl rollout status -n foundation4ai deployment/foundation4ai-api-server-worker

    Expected result: both Deployments report successfully rolled out, and the new pods are Running.

Foundation4 reports no warning before a license expires. The operator records the expiry date of each license and renews the license before that date.

License enforcement at startup​

Every process that opens a full Foundation4 connection reads the license at startup: the API server, each worker and the master key Job. The database migration Job does not read the license. A license that is malformed, issued for another system ID, of an unsupported version or expired stops the process. The error names the license, but the message starts with a database connection error:

ProcessOutput
License check JobChecking for a valid license... followed by Missing, Invalid or Expired, then the Job waits
Master key JobError: "Failed to create database connection: Invalid license"
API serverError: "Failed to initialize server: Failed to create database connection: Invalid license"
WorkerError: "Failed to connect to Foundation4.ai: Invalid license"

An expired license replaces Invalid license with Expired license. The API server and the workers also log the warning Failed to validate license for system id: <system ID>.

A license expiry does not stop running pods. A pod that restarts after the expiry, after a node failure or during a rolling update, does not start again until a valid license is installed.

HTTP 401 on POST /login is a credential error, never a license error. A license error appears either at startup or as HTTP 403.

License enforcement at runtime​

The API server checks the license before every operation that creates or changes data:

  • Checked operations. Creating and updating pipelines, text splitters, embedding models, agents, LLMs, API keys and taxonomies; creating and expiring documents; changing classifications, indexes, taxonomy entries and API key permissions; direct LLM queries.
  • Unchecked operations. Reads, searches and deletes. Agent execution and the agent retrieval dry run also run without a license check.
  • Workers. Each worker checks the expiry date before processing the documents of a pipeline. After the expiry, documents remain pending, and queued jobs are removed after 24 hours.

A refused operation returns HTTP 403 with one of the following messages. Errors describes each message.

MessageCondition
Invalid license: ExpiredThe license has expired
Invalid license: Exceeded("<types>")A cached count exceeds the limit for the named object types; every checked operation fails, whatever the object type
License limits exceeded for <type>Creating one more object of the type would exceed the limit

The API server counts objects in the following ways:

Object typesCountRefresh
Pipelines, text splitters, embedding models, agents, LLMs, API keys, taxonomiesExact countAt API server startup and every 10 minutes; each create also counts exactly
Documents, fragmentsEstimate from PostgreSQL table statistics, after ANALYZEAt API server startup and every 3 hours

Deleting objects lowers the counts at the next refresh. Restarting the API server refreshes every count at once. The workers keep no counts and check only the expiry date.

After a renewal, the client application submits again the documents that remain pending. Ingest documents reliably describes resubmission.

Troubleshooting​

Installation or upgrade waiting at the license check​

  • Symptoms. helm install or helm upgrade of the application release stops at the timeout with a failed pre-install or pre-upgrade hook, and the pod of foundation4ai-api-server-license-check stays Running.
  • Diagnosis. kubectl logs -n foundation4ai job/foundation4ai-api-server-license-check shows Checking for a valid license... followed by Missing, Invalid or Expired.
  • Cause. The license in foundation4ai-core does not match the system ID, has expired, is empty or is still the placeholder. The Job waits for 365 days so that the system ID stays in the log.
  • Resolution. Obtain a license for the system ID in the log, apply the Secret, upgrade the core release, and delete the Job with kubectl delete job -n foundation4ai foundation4ai-api-server-license-check. Then install or upgrade the application release again.
  • Actions to avoid. Repeating the application upgrade before the core release is upgraded. The core release copies the license, so the repeated upgrade checks the previous license again.

API server or workers exiting with a database connection error​

  • Symptoms. The server or worker containers restart repeatedly, and the logs report Failed to create database connection or Failed to connect to Foundation4.ai.
  • Diagnosis. kubectl logs -n foundation4ai deploy/foundation4ai-api-server -c server --previous shows whether the message ends with Invalid license or Expired license, and shows the warning with the system ID.
  • Cause. The license is not valid for the database. The database was replaced or restored, the license expired, or a restart after the expiry could not start again.
  • Resolution. Obtain a license for the system ID in the warning and follow License renewal from step 2.
  • Actions to avoid. Recreating the database or reinstalling the core release to clear the error. A new database has a new system ID and needs a new license as well.

License rejected for a license issued for the installation​

  • Symptoms. license details or the license check prints Invalid for a license that the Foundation4 provider issued for this installation.
  • Diagnosis. kubectl logs -n foundation4ai job/foundation4ai-api-server-license-check shows the current system ID. The system ID sent to the provider is compared with the current value.
  • Cause. The system ID changed after the license request: the database was recreated, restored or assigned a new schema owner. A license copied with missing or extra characters also reads as invalid.
  • Resolution. Copy the license again without line breaks. When the system ID differs, request a license for the current system ID.
  • Actions to avoid. Changing database.schema to match a system ID. The API server then computes the system ID from a different schema than the license check.

Writes refused with HTTP 403 while the license is current​

  • Symptoms. Create and update requests for several object types return HTTP 403 with Invalid license: Exceeded("<types>"), although the license has not expired.

  • Diagnosis. The following command prints the limits of the installed license. The number of objects of each named type, from the list endpoints of the API, is compared with the limit.

    kubectl exec -n foundation4ai deploy/foundation4ai-api-server -c server -- \
    ./foundation4ai license details \
    "$(kubectl get secret foundation4ai-secrets -n foundation4ai -o jsonpath='{.data.FOUNDATION4AI_APP_LICENSE}' | base64 -d)"
  • Cause. The cached count of the named object types exceeds the license limit. For documents and fragments, the count is an estimate that is refreshed every 3 hours.

  • Resolution. Delete objects of the named types and restart the API server to refresh the counts, or install a license with higher limits.

  • Actions to avoid. Creating objects of other types to test the license. Every checked operation fails while any count exceeds the limit.

Documents pending after a license renewal​

  • Symptoms. Documents submitted before or during the expiry remain pending after the renewal.
  • Diagnosis. The client application finds the documents that remain pending, as described in Ingest documents reliably. Before the workers are restarted, kubectl logs -n foundation4ai deploy/foundation4ai-api-server-worker -c worker | grep "Expired license" shows lines such as Error processing documents for pipeline <pipeline ID>: Expired license.
  • Cause. Workers stop processing after the expiry. Queued jobs are removed after 24 hours, and the documents keep the status pending.
  • Resolution. The client application submits the documents again, as described in Ingest documents reliably.
  • Actions to avoid. Restarting the workers to process the old jobs. Jobs removed from the queue are not recovered by a restart.