Issues with system/kernel/tasks/set-kernel-opts.yml in latest build

Version:

revision: 6320e157a22f47d0dad42f84e8ee58b06aa5db3f
timestamp: 1774653761
ver_maj: 3
ver_min: 2
ver_patch: 0
ver_pre: 6320e157a-dirty
dirty: true
debug: false

Fresh install on Rocky 8 failed configuring the Kernel via Ansible.

fatal: [localhost]: FAILED! => 
  msg: 'Unexpected templating type error occurred on ({{ (state | default(''present'') == ''absent'') | ternary(''Removing'', ''Adding'') }} {{ item.key }}{{ (state | default(''present'') == ''absent'') | ternary('''', '' => '' + item.value) }}): must be str, not NoneType'

Fixing the loop solved that error:

loop_control:
  label: "{{ (state | default('present') == 'absent') | ternary('Removing', 'Adding') }} {{ item.key }}{{ (state | default('present') == 'absent') | ternary('', ' => ' + (item.value | string)) }}"

Then it failed with a grub issue, turns out the regex / replace was corrupting line 6 of /etc/default/grub

fatal: [localhost]: FAILED! => changed=true 
  cmd:
  - /usr/sbin/grub2-mkconfig
  - -o
  - /etc/grub2.cfg
  delta: '0:00:00.195315'
  end: '2026-03-29 19:34:24.767710'
  msg: non-zero return code
  rc: 2
  start: '2026-03-29 19:34:24.572395'
  stderr: '/etc/default/grub: line 7: unexpected EOF while looking for matching `"'''
  stderr_lines: <omitted>
  stdout: ''
  stdout_lines: <omitted>

$] cat /etc/default/grub

GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="resume=UUID=c613f83b-c875-487f-9039-b6c4d623468d rootflags=usrquota,grpquota,prjquota" systemd.unified_cgroup_hierarchy=1"
GRUB_DISABLE_RECOVERY="true"
GRUB_ENABLE_BLSCFG=true

Line 6 should be:
GRUB_CMDLINE_LINUX="resume=UUID=c613f83b-c875-487f-9039-b6c4d623468d rootflags=usrquota,grpquota,prjquota systemd.unified_cgroup_hierarchy=1"

The regex inserted systemd.unified_cgroup_hierarchy=1 outside the closing quote instead of inside it.

At this point, I’m not a regex expert and brought in Claude to assist. While this is by no means a perfect solution, it did allow my installation to complete.

- name: Set kernel flags (strip existing value)
  replace:
    path: "{{ kernel_boot_cmdline }}"
    regexp: '{{ regex_preamble }}\s+{{ item.key | regex_escape }}=[^"''\s]+'
    replace: '\1'
  loop_control:
    label: "Stripping {{ item.key }}"
  with_dict: "{{ options | default({ option | default(omit): value | default(None)}) }}"
  when: not (rootflags | default(False))

- name: Set kernel flags (append if present)
  replace:
    path: "{{ kernel_boot_cmdline }}"
    regexp: '{{ regex_preamble }}([''"])(.*?)(\2\s*)$'
    replace: '\1\2\3 {{ item.key }}={{ item.value | string }}\4'
  loop_control:
    label: "Adding {{ item.key }}={{ item.value }}"
  with_dict: "{{ options | default({ option | default(omit): value | default(None)}) }}"
  when:
    - not (rootflags | default(False))
    - state | default('present') == 'present'
  notify: Update grub

FWIW, this was the justification provided:

The key insight: one regex cannot reliably both consume and re-emit the closing quote when it’s also optional. Splitting strip and append into two tasks eliminates the problem entirely.

This was fixed in 9db57257. You’re on an older release.

Issue is interoperability between /etc/default/grub and /etc/kernel/cmdline syntax, which to support both quoted/non-quoted forms we have to optionally reject a backreference capture. Atomic grouping is ideal, but Python lacks true support for it and the alternative syntax is garish.

-    regexp: '{{ regex_preamble }}([''"])?((?:.(?!\s*{{ option | regex_escape }}=))*.)(?:\s*{{ option | regex_escape }}=\S+)?(.*)\2$'
+    regexp: '{{ regex_preamble }}([''"])?((?:.(?!\s*{{ item.key | regex_escape }}=))*.)(?:\s*{{ item.key | regex_escape }}=\S+)?(.*)\2?$'

Usage of ? to make a backreference non-greedy, which allowed .* - greedy by default - to race to the end of the match and discard its optional backreference (shell var quoting). Inserting a non-capturing boundary marker (\b) permits backreference usage in /etc/kernel/cmdline distros.

The Owl Book is a fantastic resource if you’d like to learn more about how regexes work.

Glad to know it’s fixed. I believe I tried it on Saturday and figured I’d submit a bug report today.
I didn’t check to see if a new commit resolved it, sorry.