kestra-io/kestra · error · PebbleException

{e.getMessage()}

Error message

{e.getMessage()}

What it means

The kv(key, namespace, errorOnMissing) Pebble function retrieves a value from the Kestra KV store. If the stored key has expired (ResourceExpiredException) AND errorOnMissing is true (the default), the exception message is re-thrown as a PebbleException. When errorOnMissing is false, expired keys silently return null.

Source

Thrown at core/src/main/java/io/kestra/core/runners/pebble/functions/KvFunction.java:70

        boolean errorOnMissing = Optional.ofNullable((Boolean) args.get(ERROR_ON_MISSING_ARG)).orElse(true);

        Map<String, String> flow = (Map<String, String>) context.getVariable("flow");
        String flowNamespace = flow.get(NAMESPACE_ARG);
        String flowTenantId = flow.get("tenantId");

        Optional<KVValue> value;
        try {
            if (namespace == null) {
                namespace = flowNamespace;
                value = getValueWithInheritance(flowNamespace, key, flowTenantId);
            } else {
                // we didn't check allowedNamespace here as it's checked in the kvStoreService itself
                value = kvStoreService.get().get(flowTenantId, namespace, flowNamespace).getValue(key);
            }
        } catch (ResourceExpiredException e) {
            if (errorOnMissing) {
                throw new PebbleException(e, e.getMessage(), lineNumber, self.getName());
            }
            value = Optional.empty();
        } catch (Exception e) {
            throw new PebbleException(e, e.getMessage(), lineNumber, self.getName());
        }

        if (value.isEmpty() && errorOnMissing) {
            throw new PebbleException(null, "The key '" + key + "' does not exist in the namespace '" + namespace + "'.", lineNumber, self.getName());
        }

        return value.map(KVValue::value).orElse(null);
    }

    private Optional<KVValue> getValueWithInheritance(String flowNamespace, String key, String tenantId)
        throws IOException, ResourceExpiredException {
        Optional<KVValue> value = Optional.empty();
        String inheritedNamespace = flowNamespace;
        while (value.isEmpty()) {

View on GitHub (pinned to 823fada927)

Solutions

  1. Set errorOnMissing=false to treat expired keys the same as missing keys: {{ kv('myKey', errorOnMissing=false) }}.
  2. Rewrite the key with a new value and TTL before accessing it, or remove the TTL entirely.
  3. Check the KV store UI or API to inspect the key's expiration date.

Example fix

# before
value: "{{ kv('myKey') }}"
# after
value: "{{ kv('myKey', errorOnMissing=false) }}"
Defensive patterns

Strategy: fallback

Validate before calling

# Set errorOnMissing=false to handle expired/missing keys gracefully:
{{ kv('myKey', errorOnMissing=false) }}

Prevention

When it happens

Trigger: Calling {{ kv('myKey') }} or {{ kv('myKey', errorOnMissing=true) }} for a key that was set with a TTL that has elapsed. The key exists in the store metadata but its value has passed the expiration timestamp.

Common situations: A key was written with a short TTL for caching, and the flow references it after expiry. A developer expects the key to persist indefinitely but it was created with an expiration date.

Related errors


AI-assisted analysis of kestra-io/kestra@823fada927 (2026-08-14). Data as JSON: /api/errors/7151e1232d8b9873. Report an issue: GitHub.