For the complete documentation index, see llms.txt. This page is also available as Markdown.

Java SDK

Implement server-side feature flags in Java applications using the Harness FME Java SDK for secure, data-driven rollouts.

This guide provides detailed information about our Java SDK. All of our SDKs are open source. Go to our Java SDK GitHub repository to see the source code.

If you prefer to use the SDK as a standalone JAR file, it’s available for download from the Maven Central Repository. For example, the JAR for version 4.2.1 can be downloaded here. You can browse all available versions here.

Before you begin

The Java SDK supports JDK8 and later.

RULE-BASED SEGMENTS SUPPORT

Rule-based segments are supported in SDK versions 4.16.0 and above. No changes are required to your SDK implementation, but updating to a supported version is required to ensure compatibility.

Older SDK versions will return the control treatment for flags using rule-based segments and log an impression with a special label for unsupported targeting rules.

Initialization

To get started, set up FME in your code base using the following two steps.

1. Import the SDK into your project

Import the SDK into your project using one of the following two methods:

<dependency>
    <groupId>io.split.client</groupId>
    <artifactId>java-client</artifactId>
    <version>4.18.3</version>
</dependency>
compile 'io.split.client:java-client:4.18.3'

If you cannot find the dependency, it may be due to the lag in the sync time between Sonatype and Maven central. In this case, use the following repository:

Non-shaded version (Alternative)

If you need to manage transitive dependencies manually to resolve conflicts (e.g., with OkHttp or Guava), use the non-shaded classifier:

2. Instantiate the SDK and create a new SDK factory client

When the SDK is instantiated, it starts background tasks to update an in-memory cache with small amounts of data fetched from Harness servers. This process can take up to a few hundred milliseconds, depending on the size of data. If the SDK is asked to evaluate which treatment to show to a customer for a specific feature flag while it's in this intermediate state, it may not have the data necessary to run the evaluation. In this case, the SDK does not fail, rather, it returns the control treatment.

To make sure the SDK is properly loaded before asking it for a treatment, block until the SDK is ready. Do this by setting the desired wait using .setBlockUntilReadyTimeout() in the configuration and calling blockUntilReady() on the client. Do this all as a part of the startup sequence of your application.

We recommend instantiating the SDK factory once as a singleton and reusing it throughout your application.

Use the code snippet below with your own API key. Configure the SDK with the SDK key for the FME environment that you would like to access. In legacy Split (app.split.io) the SDK key is found on your Admin settings page, in the API keys section. Select a server-side SDK API key. See API keys to learn more.

Now you can start asking the SDK to evaluate treatments for your customers.

Use the SDK

Basic use

After you instantiate the SDK factory client, you can start using the getTreatment method of the SDK factory client to decide what version of your features your customers are served. The method requires the FEATURE_FLAG_NAME attribute that you want to ask for a treatment and a unique key attribute that corresponds to the end user that you are serving the feature to.

Then use an if-else-if block as shown below and insert the code for the different treatments that you defined in Harness FME. Remember the final else branch in your code to handle the client returning the control treatment.

Attribute syntax

To target based on custom attributes, the SDK's getTreatment method needs to be passed an attribute map at runtime.

In the example below, we are rolling out a feature flag to users. The provided attributes plan_type, registered_date, permissions, paying_customer, and deal_size are passed to the getTreatment call. These attributes are compared and evaluated against the attributes used in the Rollout plan as defined in Harness FME to decide whether to show the on or off treatment to this account.

The getTreatment method supports five types of attributes: strings, numbers, dates, booleans, and sets. The proper data type and syntax for each are:

  • Strings: Use type String.

  • Numbers: Use type java.lang.Long or java.lang.Integer.

  • Dates: Express the value in milliseconds since epoch. In Java, milliseconds since epoch is of type java.lang.Long. For example, the value for the registered_date attribute below is System.currentTimeInMillis(), which is a long.

  • Booleans: Use type java.lang.boolean.

  • Sets: Use type java.util.Collection.

Multiple evaluations at once

In some instances, you may want to evaluate treatments for multiple feature flags at once. Use the different variations of getTreatments from the SDK factory client to do this.

  • getTreatments: Pass a list of the feature flag names you want treatments for.

  • getTreatmentsByFlagSet: Evaluate all flags that are part of the provided set name and are cached on the SDK instance.

  • getTreatmentsByFlagSets: Evaluate all flags that are part of the provided set names and are cached on the SDK instance.

Get treatments with configurations

To leverage dynamic configurations with your treatments, you should use the getTreatmentWithConfig method. This method returns an object containing the treatment and associated configuration.

The config element is a stringified version of the configuration JSON defined in Harness FME. If there is no configuration defined for a treatment, the SDK returns null for the config parameter.

This method takes the exact same set of arguments as the standard getTreatment method. See below for examples on proper usage:

If you need to get multiple evaluations at once, you can also use the getTreatmentsWithConfig methods. These methods take the exact same arguments as the getTreatments methods but return a mapping of feature flag names to SplitResult instead of strings. Example usage below:

If a flag cannot be evaluated, the SDK returns the fallback treatment value (default "control" unless overridden globally or per flag). For more information, see Fallback treatments.

Append properties to impressions

Impressions are generated by the SDK each time a getTreatment method is called. These impressions are periodically sent back to Harness servers for feature monitoring and experimentation.

You can append properties to an impression by passing an object of key-value pairs to the getTreatment method. These properties are then included in the impression sent by the SDK and can provide useful context to the impression data.

Three types of properties are supported: strings, numbers, and booleans.

Shutdown

Make sure to call .destroy() before letting a process using the SDK exit as it gracefully shuts down the SDK by stopping all background threads, clearing caches, closing connections, and flushing the remaining unpublished impressions and events. The Java SDK specifically subscribes to the JVM shutdown hook (SIGTERM signal) which in normal circumstances is invoked automatically by the JVM during a shutdown process. This means that on a graceful shutdown of the server, the client will automatically call destroy() and will flush the buffers and release the resources.

In cases where you don't want our SDK to automatically destroy on shutdown, you can use the config: disableDestroyOnShutDown() (example usage in the Configuration section below) and set it to true. If you do this, the SDK ignores any signals like SIGTERM and it is your responsibility to properly call destroy at the right time. If a manual shutdown is required, you can then call:

After destroy() is called, any subsequent invocations to client.getTreatment() or manager methods result in control or empty list, respectively.

Track

Use the track method to record any actions your customers perform. Each action is known as an event and corresponds to an event type. Calling track through one of our SDKs or via the API is the first step to and allows you to measure the impact of your feature flags on your users' actions and metrics.

Refer to the Events guide for more information about using track events in feature flags.

In the examples below you can see that the .track() method can take up to five arguments. The proper data type and syntax for each are:

  • key: The key variable used in the getTreatment call and firing this track event. The expected data type is String.

  • TRAFFIC_TYPE: The traffic type of the key in the track call. The expected data type is String. You can only pass values that match the names of traffic types that you defined in Harness FME.

  • EVENT_TYPE: The event type that this event should correspond to. The expected data type is String. Full requirements on this argument are:

    • Contains 63 characters or fewer.

    • Starts with a letter or number.

    • Contains only letters, numbers, hyphen, underscore, or period.

    • This is the regular expression we use to validate the value: [a-zA-Z0-9][-_\.a-zA-Z0-9]{0,62}

  • VALUE: (Optional) The value used in creating the metric. This field can be sent in as null or 0 if you intend to only use the count function when creating a metric. The expected data type is Integer or Float.

  • PROPERTIES: (Optional) A map of key value pairs that can filter your metrics. To learn more about event property capture, refer to the Events property capture guide. FME currently supports three types of properties: strings, numbers, and booleans.

The track method returns a boolean value of true or false to indicate whether or not the SDK successfully queued the event to be sent back to Harness servers on the next event post. The SDK returns false if the current queue size is equal to the config set by eventsQueueSize or if an incorrect input to the track method is provided.

In the case that a bad input has been provided, you can read more about our SDK's expected behavior in our Events guide.

Configuration

The SDK has a number of knobs for configuring performance. Each knob is tuned to a reasonable default. However, you can override the value while instantiating the SDK. The parameters available for configuration are shown below.

Configuration

Description

Default value

featuresRefreshRate

The SDK polls Harness servers for changes to feature rollout plans. This parameter controls this polling period in seconds.

60 seconds

segmentsRefreshRate

The SDK polls Harness servers for changes to segments at this rate (in seconds).

60 seconds

impressionsRefreshRate

Controls how frequently the impressions cache expires after a write (in seconds). The treatment log captures which customer saw which treatment (on, off, etc.) and is periodically flushed back to Harness servers.

300 seconds

telemetryRefreshRate

The SDK caches diagnostic data that it periodically sends to Harness servers. This configuration controls how frequently this data is sent back to Harness servers (in seconds).

3600 seconds

eventsQueueSize

When using .track, the number of events to be kept in memory.

500

eventFlushIntervalInMillis

When using .track, how often (in milliseconds) the events queue is flushed to Harness servers.

30000 ms

connectionTimeout

HTTP client connection timeout (in ms).

15000ms

readTimeout

HTTP socket read timeout (in ms).

15000ms

setBlockUntilReadyTimeout

If specified, the client building process blocks until the SDK is ready to serve traffic or the specified time has elapsed. If the SDK is not ready within the specified time, a TimeOutException is thrown (in ms).

0ms

impressionsQueueSize

Default queue size for impressions.

30K

disableLabels

Disable labels from being sent to Harness servers. Labels may contain sensitive information.

enabled

disableIPAddress

Disable sending IP Address & hostname to the backend.

enabled

proxyHost

The location of the proxy.

localhost

proxyPort

The port of the proxy.

-1 (not set)

proxyUsername

Username to authenticate against the proxy server.

null

proxyPassword

Password to authenticate against the proxy server.

null

streamingEnabled

Boolean flag to enable the streaming service as default synchronization mechanism. In the event of an issue with streaming, the SDK falls back to the polling mechanism. If false, the SDK polls for changes as usual without attempting to use streaming.

true

impressionsMode

Defines how impressions are queued on the SDK. Supported modes are OPTIMIZED, NONE, and DEBUG. In OPTIMIZED mode, only unique impressions are queued and posted to Harness; this is the recommended mode for experimentation use cases. In NONE mode, no impression is tracked in Harness FME and only minimum viable data to support usage stats is, so never use this mode if you are experimenting with that instance impressions. Use NONE when you want to optimize for feature flagging only use cases and reduce impressions network and storage load. In DEBUG mode, all impressions are queued and sent to Harness; this is useful for validations. Use DEBUG mode when you want every impression to be logged in Harness FME when trying to debug your SDK setup. This setting does not impact the impression listener which receives all generated impressions locally.

OPTIMIZED

operationMode

Defines how the SDK synchronizes its data. Two operation modes are currently supported: - STANDALONE - CONSUMER

STANDALONE

storageMode

Defines what kind of storage the SDK is going to use. With MEMORY, the SDK uses its own storage and runs as STANDALONE mode. Set REDIS mode if you want the SDK to run with this implementation as CONSUMER mode.

MEMORY

flagSetsFilter

This setting allows the SDK to only synchronize the feature flags in the specified flag sets, avoiding unused or unwanted flags from being synced on the SDK instance, bringing all the benefits from a reduced payload.

null

threadFactory

Defines what kind of thread the SDK is going to use. Allows the SDK to use Virtual Threads.

null

inputStream

This setting allows the SDK supports InputStream to use localhost inside a JAR.

null

FileTypeEnum

Defines which kind of file is going to be the inputStream. Supported files are YAML and JSON for inputStream.

null

To set each of the parameters defined above, use the following syntax:

Localhost mode

For testing, a developer can put code behind feature flags on their development machine without the SDK requiring network connectivity. To achieve this, the SDK can be started in localhost mode (aka off-the-grid mode). In this mode, the SDK neither polls nor updates Harness servers. Instead, it uses an in-memory data structure to determine what treatments to show to the logged in customer for each of the features. To use the SDK in localhost mode, you must replace the API Key with "localhost" value.

With this mode, you can instantiate the SDKS using one of the following methods:

  • JSON: Full support, for advanced cases or replicating an environment by pulling rules from Harness FME servers (from version 4.7.0).

  • YAML: Supports dynamic configs, individual targets and default rules (from version 3.1.0).

  • .split: Legacy option, only treatment result.

JSON

Since version 4.7.0, our SDK supports localhost mode by using the JSON format. This version allows the user to map feature flags and segment definitions in the same format as the APIs receive the data.

This new mode needs extra configuration to be set:

Name

Description

Type

splitFile

Indicates the path of the feature flags file location to read

String

segmentDirectory

Indicates the path where all the segment files are located

String

localhostRefreshEnabled

Flag to run synchronization refresh for feature flags and segments in localhost mode.

Boolean

splitFile

The following splitFile is a JSON that represents a SplitChange:

segmentDirectory

The provided segment directory must have the json files of the corresponding segment linked to previous feature flag definitions. According to the file sample above: feature_flag_1 has segment_1 linked. That means that the segmentDirectory needs to have segment_1 definition.

YAML

Since version 3.1.0, our SDK supports a type of localhost feature flag definition file that uses the YAML format. This new format allows the user to map different keys to different treatments within a single feature flag and also add configurations to them. The format is a list of single-key maps (one per mapping feature-flag-keys-config) which is defined as follows:

In the example above, we have four entries:

  • The first entry defines that for feature flag my_feature_flag, the key key returns the treatment on and the on treatment is tied to the configuration {"desc" : "this applies only to ON treatment"}.

  • The second entry defines that the feature flag some_other_feature_flag always returns the off treatment and no configuration.

  • The third entry defines that my_feature_flag always returns off for all keys that don't match another entry (in this case, any key other than key).

  • The fourth entry shows how an example overrides a treatment for a set of keys.

Use the SplitConfigBuilder object to set the location of the localhost YAML file as shown in the example below:

.SPLIT file

In this mode, the SDK loads a mapping of feature flag name to treatment from a file at $HOME/.split. For a given flag, the treatment specified in the file is returned for every customer.

getTreatment calls for a feature flag and only returns the one treatment that you defined in the file. You can then change the treatment as necessary for your testing in the file. Any feature that is not provided in the features map returns the control treatment if the SDK is asked to evaluate them.

The format of this file is two columns separated by a whitespace. The left column is the feature flag name and the right column is the treatment name. The following is a sample .split file:

Input Stream

Since version 4.9.0, the SDK supports InputStream to use localhost inside a JAR. To achieve this, we added new parameters in splitFile property to set the InputStream. The first param is an InputStream of the file that we want to read. And the second is a FileTypeEnum which can be either YAML, or JSON. Here is an example code to demonstrate how to use this new feature:

State Sharing: Redis Integration

Before you get started with the cache, download the correct version of Redis to your machine. Make sure to start your Redis server. Refer to the Redis documentation for help. After that, followi the additional three steps to set up the cache with Redis.

1. Install the Redis Wrapper into your project

Import the Redis Wrapper into your project using one of the two methods below:

2. Set up the Split Synchronizer

Set up the Split Synchronizer to sync data to a Redis cache. Once you set up the synchronizer, go to the following step #3 to instantiate:

3. Instantiate the SDK factory client with Redis enabled

To run the SDK with Redis, you need to provide the Redis storage wrapper. Refer to the following to provide the wrapper:

Redis wrapper configuration

When you create a new instance for the Redis wrapper, you can provide your own configurations for some values.

Field name(s)

Description

Default value

timeout

Timeout that the connections is going to handle.

1000

host

Hostname where the Redis instance is.

localhost

port

HTTP port used in the connection.

6379

database

Numeric database to be used.

0

user

Redis cluster user. Leave empty if no User is used.

""

password

Redis cluster password. Leave empty if no password is used.

""

prefix

Best practice is to use a prefix in case the Redis instance is shared by many SDKs.

""

jedisPool

You can provide your own implementation of JedisPool.

null

maxTotal

Max number of pool connections.

8

Redis cluster support

The SDK supports Redis with Cluster. Note that a stable release of Cluster has shipped since Redis 3.0. For further information about Redis Cluster, refer to the Cluster documentation.

Use the following configuration for Redis in Cluster mode.

Variable

Type

Description

clusterNodes

Set<HostAndPort>

The list of cluster nodes.

jedis

JedisCluster

Jedis contains the list of cluster nodes.

keyHashTag

string

Custom hashtag to be used.

REDIS CLUSTER

The Java SDK performs multi-key operations in certain methods such as mget (to return values of all specified keys) or keys (to return all the keys that matches a particular pattern) to avoid multiple calls to Redis. Redis Cluster does not allow these operations unless you use hashtags. Hashtags ensure that multiple keys are allocated in the same hash slot. The SDK allows you to use a custom key hashtag for storing keys. If this option is missing, it uses a default hashtag of {SPLITIO} when cluster mode is specified in the configuration. Keep in mind that multi-key operations may become unavailable during a resharding of the hash slots, calls to getTreatments, or manager.splitNames(), causing splitKeys to fail.

Manager

Use the Split Manager to get a list of features available to the SDK factory client.

To instantiate a Manager in your code base, use the same factory that you used for your client.

The Manager then has the following methods available:

The SplitView object that you see referenced above has the following structure:

Listener

FME SDKs send impression data back to Harness servers periodically and as a result of evaluating feature flags. To additionally send this information to a location of your choice, define and attach an impression listener.

The SDK sends the generated impressions to the impression listener immediately. As a result, be careful while implementing handling logic to avoid blocking the main thread. As the second parameter, specify the size of the queue acting as a buffer (see the snippet below).

If the impression listener is slow at processing the incoming data, the queue fills up and any subsequent impressions are dropped.

Logging

The Java SDK uses slf4j-api for logging. If you do not provide an implementation for slf4j, you see the following error in your logs:

You can get the SDK to log by providing a concrete implementation for SLF4J. For instance, if you are using log4j, you should import the following dependency.

If you have a log4j.properties in your classpath, the SDK log is visible. The following is an example of log4j.properties entry:

The following is an example of initializing the logger object in Java:

Thread Factory

Since version 4.10.0, the Java SDK provides support for Virtual Threads using the config threadFactory, instead of traditional threads. Below is an example of how to set it up:

Configure fallback treatments

Fallback treatments let you define a treatment value (and optional configuration) to be returned when a flag cannot be evaluated. By default, the SDK returns control, but you can override this globally or for individual flags at the SDK level.

This is useful when you want to:

  • Maintain a predictable user experience during outages or evaluation failures (avoid unexpected control in production)

  • Protect critical user flows by returning a safe, stable treatment (for example, forcing off during an incident)

  • Customize behavior per flag so each evaluation inherits appropriate safe defaults if something goes wrong

Global fallback treatment

Set a global fallback treatment when initializing the SDK factory. This value is returned whenever any flag cannot be evaluated.

Flag-level fallback treatment

You can also set a fallback treatment per flag when calling getTreatment or getTreatmentWithConfig. This flag-level fallback always takes precedence over the global fallback treatment, so if both are defined, the SDK will return the flag-level value when that flag cannot be evaluated.

For more information, see Fallback treatments.

Integrations

New Relic

The New Relic integration annotates New Relic transactions with FME feature flags information that can be used to correlate application metrics with feature flag changes. This integration is implemented as a synchronous impression listener and it can be enabled as shown below:

This integration is only enabled if the SDK detects the New Relic agent in the classpath. If the agent is not detected, the following error will be displayed in the logs (if logging is enabled):

Proxy

If your environment requires routing traffic through a proxy, you can configure the Java SDK to use one.

If you need to use a standard network proxy, set the proxyHost and proxyPort options in the SDK configuration. The SDK uses these values to perform requests through the proxy.

Connect to a Split Proxy instance

You can also connect the SDK to a Split Proxy instance instead of connecting directly to Harness FME servers. The Proxy synchronizes data and writes impressions and events back to Harness.

Use the .endpoint() property in the SplitClientConfig builder object to point the Java SDK to the Proxy endpoint, and specify the same port used in the Proxy command line. When creating the SplitFactory object, use the custom API key defined in the Proxy's client-apikeys parameter. The Proxy uses the SDK key when connecting to Harness FME servers.

To simplify maintenance and future updates, define your Proxy configuration using separate variables:

  • Base endpoint (for .endpoint())

  • Auth path (/api/v2/auth)

  • Telemetry path (/api/v1)

This makes it easier to update paths or environments without changing multiple hardcoded values.

Integrate with the Harness Proxy

The Harness Proxy allows SDK traffic to securely route through a centralized, authenticated point before reaching the Harness SaaS backend. This provides full visibility and control over network traffic while keeping API keys secure and isolated.

To use the proxy, configure the SDK to point to the proxy host and port during initialization. All SDK requests are then routed through the proxy.

Configure the proxy

You can configure the Java SDK to route traffic through a forward proxy using the ProxyConfiguration class builder. This allows you to define proxy URLs, authentication credentials, and optional mTLS settings.

The following proxy configuration parameters are available:

Configuration
Description
Required

url

Proxy server URL, provided as an instance of the java.net.URL class.

Yes

credentialsProvider

Credentials used for proxy authentication. Provide an implementation of either BearerCredentialsProvider or BasicCredentialsProvider.

Optional

mtls

Parameters for mTLS authentication, including the .p12 certificate file and password.

Optional

Harness Proxy (URL Only)

To use a proxy with no authentication, specify only the proxy URL in the configuration. Follow the pattern: http(s)://host:port.

Authentication is optional. Only one authentication method can be active at a time.

Harness Proxy with Username/Password Authentication

To authenticate using a username and password, implement the BasicCredentialsProvider interface and override the required methods.

Harness Proxy with JWT Token Authentication

To authenticate using a JWT, implement the BearerCredentialsProvider interface and override the getToken() method to return a valid JWT string.

Refresh or update the token when it expires.

Harness Proxy with mTLS Authentication

To configure mutual TLS (mTLS) authentication, use the mtls() parameter to pass the .p12 certificate file and its password.

Verify connection

After initialization, all SDK requests are routed through the configured proxy. You can verify successful routing by checking your proxy logs or a network monitor for SDK traffic.

Advanced: WebLogic container

WebLogic and the Java SDK contain a reference to Google Guava. If you are currently deploying a web application that contains our Java SDK into WebLogic, instruct the container to load Guava from the app classpath and not from the container.

If you have an existing weblogic.xml file in your deployment, add: <package-name>com.google.common.*</package-name> under the <prefer-application-packages> tag. If you do not, create the file and place it under the directory WEB-INF.

Here is a sample of a weblogic.xml file that includes the previously mentioned Guava classpath loading instruction.

Troubleshooting

Timeout Error: NoSuchMethodError: com.google.common.collect.Multisets.removeOccurrences

Using the Java SDK within certain frameworks, the SDK always times out. The logs show the following error:

This error happens because the Java SDK depends on the Google Guava library version 19.0 or higher. If your framework uses an older Guava version (< 19.0), this method will be missing, causing the error.

Upgrade the Google Guava dependency in your project to version 19.0 or above to resolve this issue.

How to change log level in the Java SDK

When integrating the Java SDK into a framework that uses Log4J, the SDK outputs many debug lines. Is it possible to change the log level?

Yes. The Java SDK respects the log4j.properties configuration file used by your Java application. To reduce logging verbosity and set the log level to ERROR, add these lines to your log4j.properties file:

This will suppress debug and info logs from the SDK, showing only error messages.

Error using JRE 6.x: "fatal alert: handshake_failure"

Using the Java SDK with JDK 1.6 (JRE 6.x), you may encounter the following SSL connection error when trying to connect to split.io:

Java 1.6 supports TLSv1 but does not support the high-strength ciphers required by split.io’s security protocol.

To fix this issue, you have two options:

  1. Upgrade your JDK to version 1.7 or above. These versions include support for the stronger ciphers by default.

  2. If upgrading is not an option, install the Java Cryptography Extension (JCE) provided by your JVM vendor for Java 6 to enable support for high-strength ciphers.

Exception: PKIX path building failed

When initializing the Java SDK SplitFactory object, you may see the following error:

This indicates that Java could not verify the SSL certificate from Split.io, preventing a secure connection between the SDK and Harness FME servers.

Manually install Split.io's certificates into your JVM’s trust store:

  1. Download the certificates for both sdk.split.io and events.split.io:

  2. Import the certificates into the Java cacerts keystore (replace [JAVA_HOME] with your Java installation path):

  3. Restart your Java application.

Certificate renewals

Harness FME relies on Split.io's managed certificates for secure SDK communication. When Split.io rotates or renews its certificates, your application should continue working if:

  • Your JVM's default trust store already contains the required certificate authorities (most modern JDKs do).

  • Or, you've installed the intermediate/root certificates instead of the short-lived leaf certificates.

However, if you manually imported specific leaf certificates, you'll need to repeat the steps above when Split.io updates them. To avoid manual updates, consider updating your JDK to the latest version so its default trust store includes up-to-date CAs.

Check certificate expiry proactively

To see when Split.io's certificates expire, run:

This outputs something like the following:

If the notAfter date is approaching and you manually imported certificates, repeat the installation steps above.

Last updated

Was this helpful?