Krikri::ErrorBlock
Matches ansible-core 2.19's task-failure error-block
rendering: Display._error -> _display_utils.format_message ->
_event_formatting.format_event/format_event_verbose_message, over
an Event tree whose source context comes from
_error_utils.SourceContext.from_origin. This is what
ansible-playbook prints as
[ERROR]: Task failed: <message> ... Origin: <file>:<line>:<col> ... <<< caused by >>> ...
before the fatal: line whenever a task failure carries an
exception event (controller/action exceptions, module failures
wrapped by the module API, conditional-evaluation failures).
The event tree is small (a message, its optional source context, and a linear cause chain); every shape Ansible 2.19 produces for task failures is one of:
- collapsed: the whole cause chain collapses into one segment ("Task failed: Module failed: non-zero return code" + the task origin), when every chained event shares the direct-cause reason and carries no distinct source context.
- handling: the chain breaks at an event whose own chain reason
differs ("raise X(...) from Y" vs a bare
raise X(...)insideexcept Y), producing the two-segment form with the<<< caused by >>>separator (template action failures, conditional-evaluation failures).
Constants
Ansible composes its "Valid booleans include: ..." enumeration from
a Python SET (BOOLEANS in module_utils/parsing/convert_bool.py),
whose iteration order is randomized per PROCESS. A MODULE runs in a
fresh process per invocation on the target, so one module-level bool
failure never renders the same text twice and Display._deduplicate
cannot collapse two of them: a loop's identical failed items - and
the same failure on several hosts - each print their own block
(live-verified vs ansible-core 2.21.6, issue #952: five expect: items
gave five blocks with five orderings, two hosts gave two). krikri
keeps this enumeration's order fixed (see
PluginHelpers::StrictBoolValidation), so its rendering of the same
failures WOULD dedupe - hence the exemption in record_displayed.
The identical wording raised controller-side (set_fact's cacheable:, gather_facts' parallel:) comes from the one long-lived controller process, whose set order never changes, so real DOES collapse those repeats into a single block (live-verified vs 2.21.6). Only the module-rendered chain carries the "Module failed: " segment, which is what separates the two.
Class methods
Matches _event_utils.deduplicate_message_parts.
Renders the event tree into Ansible's [ERROR]: ... block and
prints it, unless the exact text was already displayed (Ansible's
Display._deduplicate - one global set, so a loop's per-item
failures with identical text, or the same failure on several hosts,
display the block once). Returns true when printed.
Same dedup and STDERR routing as emit_stderr, for a block already rendered at its raise site (a RemovedModuleError's render carries the Origin context the raise site built from the source map).
Same rendering and dedup as emit, but on STDERR. Ansible routes an error block to stderr when the error is raised OUTSIDE task result processing - a dynamic include_role:'s role resolution failure ("The role 'x' was not found in: ...") - while ordinary task-failure blocks go to stdout (live-verified vs 2.21.6).
emit variant capturing to an IO instead of printing: TaskExecutor's unreachable report buffers its block (run_task_batch books unreachable hosts before it knows the task banner is coming, and ansible prints the report under that banner).
Matches _event_formatting.format_event_verbose_message.
A Node owns its outgoing chain link (chain/chain_reason/
chain_follow mirror EventChain.event/msg_reason/follow),
so the traversal walks node-as-link-owner pairs exactly the way
the Python walks EventChain objects.
Matches _event_formatting._get_message_lines.
Matches _error_utils.SourceContext.from_origin + #to_s:
Origin: path:line:col, a blank line, then up to 2 lines of
context before the target line (right-aligned line numbers, tabs
collapsed to single spaces, 120-column truncation with a ...
marker) and the caret line under the target column. Returns the
block WITHOUT a trailing newline.