kestra-io/kestra · error · PebbleException

The 'secret' function cannot be called with both 'subkey' an

Error message

The 'secret' function cannot be called with both 'subkey' and 'full' arguments.

What it means

The secret() function supports two modes: retrieving a single sub-key from a JSON secret (via 'subkey') or retrieving the full secret object with metadata (via 'full=true'). These modes are mutually exclusive because 'full' returns the entire secret as a structured object while 'subkey' extracts one field. Passing both makes the intent ambiguous and is rejected.

Source

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

    public Object execute(Map<String, Object> args, PebbleTemplate self, EvaluationContext context, int lineNumber) {
        String key = getSecretKey(args, self, lineNumber);
        String namespace = (String) args.get(NAMESPACE_ARG);

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

        if (namespace == null) {
            namespace = flowNamespace;
        } else {
            namespaceService.get().checkAllowedNamespace(flowTenantId, namespace, flowTenantId, flowNamespace);
        }

        final String subkey = (String) args.get(SUBKEY_ARG);
        final boolean full = Boolean.TRUE.equals(args.get(FULL_ARG));

        if (full && subkey != null && !subkey.isEmpty()) {
            throw new PebbleException(null, "The 'secret' function cannot be called with both 'subkey' and 'full' arguments.", lineNumber, self.getName());
        }

        try {
            if (full) {
                SecretObject secretObject = secretService.get().findSecretObject(flowTenantId, namespace, key);
                consumeSecret(context, secretObject.value());

                Map<String, Object> result = new LinkedHashMap<>();
                result.put(VALUE_KEY, secretObject.value());
                if (!secretObject.metadata().isEmpty()) {
                    secretObject.metadata().values().forEach(value -> consumeSecret(context, value));
                    result.put(METADATA_KEY, secretObject.metadata());
                }
                return result;
            }

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

View on GitHub (pinned to 823fada927)

Solutions

  1. Remove the 'subkey' argument when using full=true: {{ secret('MY_KEY', full=true) }}.
  2. Or remove the 'full' argument when using subkey: {{ secret('MY_KEY', subkey='password') }}.
  3. If branching logic needs both modes, use an if/else in Pebble to select one path at a time.

Example fix

# before
{{ secret('MY_KEY', subkey='password', full=true) }}

# after — choose one mode
{{ secret('MY_KEY', subkey='password') }}
# or
{{ secret('MY_KEY', full=true).value }}
Defensive patterns

Strategy: validation

Validate before calling

# Never pass both subkey and full to secret().
# Use conditional logic to select one mode:
{% if inputs.full_mode %}{{ secret(inputs.key, full=true) }}{% else %}{{ secret(inputs.key, subkey=inputs.subkey) }}{% endif %}

Prevention

When it happens

Trigger: Calling {{ secret('MY_KEY', subkey='password', full=true) }}. The 'full' argument resolves to true (either explicitly or via a variable) at the same time subkey is a non-empty string.

Common situations: Gradually migrating from subkey-based access to full-object access and forgetting to remove the old subkey argument. A flow input or variable populating both arguments conditionally. Template reuse where one branch sets subkey and another sets full, and both are active.

Related errors


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