flowable/flowable-engine · error · IllegalArgumentException

ackMode in definition [ <channelDefinition> ] must resolve t

Error message

ackMode in definition [ <channelDefinition> ] must resolve to a String or AcknowledgeMode

What it means

The ackMode attribute of a Rabbit inbound channel definition, when set (even as an expression), must resolve to either a String naming an AcknowledgeMode enum value or an AcknowledgeMode instance itself. Any other resolved type makes resolveAckMode throw this IllegalArgumentException.

Source

Thrown at modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/rabbit/RabbitChannelDefinitionProcessor.java:246

                throw new IllegalArgumentException("Could not register rabbit listener endpoint on [" +
                    channelDefinition + "], no " + RabbitAdmin.class.getSimpleName() + " with id '" +
                    rabbitAdmin + "' was found in the application context", ex);
            }
        } else {
            return null;
        }
    }

    protected AcknowledgeMode resolveAckMode(RabbitInboundChannelModel channelDefinition) {
        String ackModeAttr = channelDefinition.getAckMode();
        if (StringUtils.hasText(ackModeAttr)) {
            Object ackMode = resolveExpression(ackModeAttr);
            if (ackMode instanceof String) {
                return AcknowledgeMode.valueOf((String) ackMode);
            } else if (ackMode instanceof AcknowledgeMode) {
                return (AcknowledgeMode) ackMode;
            } else {
                throw new IllegalArgumentException("ackMode in definition [ " + channelDefinition + " ] must resolve to a String or AcknowledgeMode");
            }
        } else {
            return null;
        }
    }

    protected TaskExecutor resolveExecutor(RabbitInboundChannelModel channelDefinition) {
        String executorBeanName = resolve(channelDefinition.getExecutor());
        if (StringUtils.hasText(executorBeanName)) {
            Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve TaskExecutor by bean name");
            try {
                return this.beanFactory.getBean(executorBeanName, TaskExecutor.class);
            } catch (NoSuchBeanDefinitionException ex) {
                throw new IllegalArgumentException("Could not register rabbit listener endpoint on [" +
                    channelDefinition + "], no " + TaskExecutor.class.getSimpleName() + " with id '" +
                    executorBeanName + "' was found in the application context", ex);
            }
        } else {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Set ackMode to a valid string enum name: AUTO, MANUAL, or NONE
  2. Reference an AcknowledgeMode bean directly in the definition
  3. Fix the expression/placeholder so it resolves to the correct type
  4. Check the config serialization so ackMode is emitted as a string, not a number/boolean

Example fix

// before
"ackMode": true
// after
"ackMode": "AUTO"
Defensive patterns

Strategy: validation

Validate before calling

Object ack = resolveExpression(channelDefinition.getAckMode());
if (ack != null && !(ack instanceof String) && !(ack instanceof AcknowledgeMode)) {
    throw new IllegalArgumentException("ackMode must be a String enum name or AcknowledgeMode");
}
if (ack instanceof String) { AcknowledgeMode.valueOf((String) ack); } // validates enum name early

Type guard

boolean isValidAckMode(Object v) {
    return v instanceof AcknowledgeMode || (v instanceof String && Arrays.stream(AcknowledgeMode.values()).anyMatch(m -> m.name().equals(v)));
}

Try / catch

try {
    processor.process(definition);
} catch (IllegalArgumentException ex) {
    if (ex.getMessage().contains("ackMode")) {
        log.error("Bad ackMode in {}: {}", definition, ex.getMessage());
    }
    throw ex;
}

Prevention

When it happens

Trigger: channelDefinition.getAckMode() expression resolves to a non-String/non-AcknowledgeMode object (e.g. Integer, Boolean) while processing the channel definition in createRabbitListenerEndpoint.

Common situations: Config file storing ackMode as a boolean or number; placeholder resolving to the wrong bean; confusion between ack mode names and other frameworks' ackMode types.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/73be483acd63a008. Report an issue: GitHub.