kestra-io/kestra · error · SecretException

Failed to read secret sub-key '%s' from secret '%s'. Ensure

Error message

Failed to read secret sub-key '%s' from secret '%s'. Ensure the secret contains valid JSON value.

What it means

When the secret() function is called with a 'subkey' argument, it attempts to parse the secret value as JSON using Jackson ObjectMapper.readTree(). If the secret is not valid JSON (e.g., a plain string, a number, or malformed JSON), a JsonProcessingException is caught and re-thrown as a SecretException with this message. This means the secret was found but its content cannot be interpreted as a JSON object for sub-key extraction.

Source

Thrown at core/src/main/java/io/kestra/core/runners/pebble/functions/SecretFunction.java:103

                    secretObject.metadata().values().forEach(value -> consumeSecret(context, value));
                    result.put(METADATA_KEY, secretObject.metadata());
                }
                return result;
            }

            String secret = secretService.get().findSecret(flowTenantId, namespace, key);

            if (subkey != null && !subkey.isEmpty()) {
                try {
                    JsonNode subkeys = OBJECT_MAPPER.readTree(secret);
                    if (!subkeys.has(subkey)) {
                        throw new SecretNotFoundException("Cannot find secret sub-key '" + subkey + "' in secret '" + key + "'.");
                    } else {
                        JsonNode jsonNode = subkeys.get(subkey);
                        secret = jsonNode.isValueNode() ? jsonNode.asText() : jsonNode.toString();
                    }
                } catch (JsonProcessingException e) {
                    throw new SecretException(
                        String.format(
                            "Failed to read secret sub-key '%s' from secret '%s'. Ensure the secret contains valid JSON value.",
                            subkey,
                            key
                        )
                    );
                }
            }

            consumeSecret(context, secret);
            return secret;
        } catch (SecretException | IOException e) {
            throw new PebbleException(e, e.getMessage(), lineNumber, self.getName());
        }
    }

    @SuppressWarnings("unchecked")
    private void consumeSecret(EvaluationContext context, String value) {

View on GitHub (pinned to 823fada927)

Solutions

  1. If the secret is a single value, access it without subkey: {{ secret('API_TOKEN') }}.
  2. If you need sub-key access, re-store the secret as a JSON object: {"key":"sk-abc123"}.
  3. Verify the secret content in the secret backend to confirm it is valid JSON.

Example fix

# before — secret value is a plain string, not JSON
{{ secret('API_TOKEN', subkey='key') }}

# after — access the raw value directly
{{ secret('API_TOKEN') }}
# or re-store as JSON: {"key":"sk-abc123"}
{{ secret('API_TOKEN', subkey='key') }}
Defensive patterns

Strategy: validation

Validate before calling

# Only use subkey on secrets known to contain valid JSON.
# If unsure, access the raw value first:
# {{ secret('MY_KEY') }}
# If the value is not JSON, re-store it as JSON in the secret backend before using subkey.

Prevention

When it happens

Trigger: Calling {{ secret('API_TOKEN', subkey='key') }} when the secret value is a plain string like 'sk-abc123' (not JSON). The secret was stored as a raw value rather than a JSON object. The secret value contains truncated or corrupted JSON.

Common situations: Secret originally stored as a single value (token, password) but later accessed with a subkey as if it were a JSON object. Secret migration from one backend to another that changed the format. A team member stored a secret without JSON structure.

Related errors


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