Skip to content

check-rd-presets reports a present preset as missing when grep -q closes the pipe first #4158

Description

hack/check-rd-presets.sh can report a preset as missing while it is present in the file. It fired on a PR that touches no RD schema and turned Unit & controller tests red.

What the log showed:

hack/check-rd-presets.sh: line 39: printf: write error: Broken pipe
FAIL: packages/system/nats-rd/cozyrds/nats.yaml resourcesPreset enum missing: u1.nano

u1.nano is in that enum, both on the branch and on main. Running the same script against the same tree locally prints All RD schemas carry the full 47-preset enum.

The script sets set -euo pipefail on line 7, and line 39 is the membership test:

if ! printf '%s\n' "$enums" | grep -Fqx -- "$want"; then

grep -q exits as soon as it matches and closes the read end of the pipe. If printf has not finished writing by then it takes SIGPIPE and exits 141. Under pipefail the pipeline reports 141 instead of grep's 0, the ! inverts that into true, and a preset that was found gets recorded as missing. Whether printf completes its write before grep leaves is down to scheduling, so the same tree passes on one run and fails on the next.

Reproducer, deterministic because the larger input makes the write outlive grep:

$ bash -c 'set -euo pipefail; big=$(seq 1 200000)
if ! printf "%s\n" "$big" | grep -Fqx -- "1"; then echo MISSING; fi'
MISSING

1 is in that list. The same pipeline under plain set -o pipefail returns 141.

Two shapes fix it and I verified both against the reproducer: drop the pipe with grep -Fqx -- "$want" <<< "$enums", or do the membership test in bash with no external process at all.

Worth naming separately: the failure message points the reader at make generate in a chart they never touched, and the schema there is already correct, so there is nothing to regenerate. The wrong diagnosis costs more than the red itself.

The same printf | grep -q shape appears in other scripts that set pipefail, but their input is a single line, where the race is much less likely. I have not measured those.

Correction to the first version of this issue, which claimed the race explains the CI failure. I went and measured it at the size this script actually handles, and it does not reproduce: 3000 runs, then 3000 more with the CPU saturated the way a parallel make saturates a runner, zero false results. The largest enum any RD file yields is 3009 bytes (seaweedfs), well inside the 64 KiB pipe buffer, so printf finishes its single write before grep can leave and there is no SIGPIPE for it to take. The reproducer above still holds, but it needs an input far larger than anything this script sees.

So the mechanism behind that CI failure is not established, and the first version of this text asserted it was. What is established: the construct really does return 141 under pipefail when a write outlives its reader; the CI log carries that exact error on that exact line; and the preset it reported missing is present in the file, on the branch and on main. Whatever made the write fail there, the pipeline converts it into a wrong answer about the schema instead of surfacing it as a broken read.

That is the part worth fixing regardless of which cause is found. Removing the pipe removes the path by which any write error becomes a false "missing" — and it removes it without anyone having to first explain the write error.

Activity

  1. lexfrei commented on Sep 8, 2026

    @lexfrei
    ContributorAuthor

    Duplicate of #4153, which was filed an hour earlier on the same line. The measurement from here is carried over as a comment there: the race does not reproduce at this input size, so the cause of the red jobs is still unestablished, while the construct is worth fixing either way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/bugCategorizes issue or PR as related to a bugtriage/needs-triageIndicates an issue needs triage by a maintainer

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions