Skip_queue_config_hook=true -> Validation failed

Aloha KumoMTA Team :man_bowing:

To start with, the entire init.lua configuration works completely fine with skip_queue_config_hook = true set, according to the recommendation.
The problem only affects the configuration verification via kumod --validate --policy /opt/kumomta/etc/policy/init.lua command.
Even though everything runs correctly, the validation fails. I understand that the order matters here, but the declaration

local queue_helper = queue_module:setup_with_options { 
    skip_queue_config_hook = true,
    file_names = { '/opt/kumomta/etc/policy/queues.toml', },
}

…is actually the last one. However, this probably shouldn’t matter anyway because get_queue_config is skipped in queue_helper.

2026-05-26T09:22:14.573678Z  INFO localset-0 kumod: Version is 2026.04.09-ea3b2a9b
2026-05-26T09:22:14.573712Z  INFO localset-0 kumod: NodeId is b689113c-d829-4a0c-8d89-5657189d3f0f
2026-05-26T09:22:14.573787Z  INFO localset-0 kumod: available_parallelism=8
2026-05-26T09:22:14.578206Z  INFO localset-0 kumod::logging::classify: bounce-classify thread pool starting with 2 threads
queue.lua is in use, but it is not the last module to register for the get_queue_config event.
This can cause issues with routing/scheduling, especially if you have a [queue.default]
block defined in your queue data.

Here are the locations where each of the get_queue_config events are
registered:

1:
    /opt/kumomta/share/policy-extras/log_hooks.lua:191
    [string "/opt/kumomta/etc/policy/init.lua"]:20
2:
    /opt/kumomta/share/policy-extras/shaping.lua:540
    [string "/opt/kumomta/etc/policy/init.lua"]:118
3:
    [string "/opt/kumomta/etc/policy/init.lua"]:185

You should adjust the initialization order so that queue.lua is last.

2026-05-26T09:22:14.635810Z  INFO       main kumod::spool: Shutting down spool
Error: Initialization raised an error: Validation failed

The command returns Error: Initialization raised an error: Validation failed and exit code 1, which prevents me from verifying the configuration validity in the pipeline before deployment.

[queue.default] is commented out.

At first glance, this does not look like a configuration error (everything works as it should).

Does the validation take skip_queue_config_hook = true into account?

The exact same configuration but with skip_queue_config_hook = false passes validation without any errors.

What else could have gone wrong?

This looks like a validation false positive rather than a runtime configuration problem.

With skip_queue_config_hook = true, queue.lua intentionally does not register a get_queue_config handler. The validation output confirms that: the
get_queue_config registrars are log_hooks.lua, shaping.lua, and my init.lua handler, but not queue.lua.

However, queue.lua’s validate_config logic still appears to run the “queue.lua must be the last get_queue_config registrar” check unconditionally
once the queue module is configured. Since queue.lua did not register a handler, the check cannot find queue.lua in the registrar list, so my_reg
is nil, and nil ~= #reg causes validation to fail.

That explains why the same configuration passes when skip_queue_config_hook = false: in that mode queue.lua does register get_queue_config, and if
setup_with_options is last, queue.lua becomes the last registrar.

So the question “does validation take skip_queue_config_hook into account?” appears to be: not fully / not correctly. The order shown in the
validation output actually looks correct for the skip mode: log_hooks and shaping register first, then the custom init.lua get_queue_config
handler acts as the final fallback.

A reasonable fix in queue.lua would be to skip this order check when options.skip_queue_config_hook is true, or only run it when queue.lua
actually registered a get_queue_config handler.