Redirection failing if |& is used instead of | (pipe) - bash bug?

tl;dr

Not a bug. |& is like an alias for 2>&1 |, a shorthand, a way to type less. Note 2>&1 is now the final redirection in this part of the pipeline. That's all.


Analysis

The following citation is quite clear to me. You need to read the whole of it. In the question you cited few sentences without the broader context.

The output of each command in the pipeline is connected via a pipe to the input of the next command. That is, each command reads the previous command’s output. This connection is performed before any redirections specified by the command.

If |& is used, command1’s standard error, in addition to its standard output, is connected to command2’s standard input through the pipe; it is shorthand for 2>&1 |. This implicit redirection of the standard error to the standard output is performed after any redirections specified by the command.

(emphasis mine, source link)

Take foo … |& bar, where denotes redirections specified by the command. |& is a shorthand (think: "alias") for 2>&1 |, so the command is like foo … 2>&1 | bar; and the foo part is like

foo >fifo … 2>&1

where >fifo denotes the connection to the stdin of bar (I used the name fifo but in fact it's an anonymous pipe).

There is no deeper philosophy, |& simply "expands" to 2>&1 |. Then | behaves like >fifo before ("this connection is performed before any redirections specified by the command") and 2>&1 stays at the end ("this implicit redirection of the standard error to the standard output is performed after any redirections specified by the command"). In general redirections are performed from left to right, so >fifo … 2>&1 is a good representation of what happens.


Example: your command

Your command:

strace echo something 2>&1 >/dev/null |& wc -l

"expands" to:

strace echo something 2>&1 >/dev/null 2>&1 | wc -l

and the strace part behaves like:

strace echo something >fifo 2>&1 >/dev/null 2>&1

where >/dev/null 2>&1 redirects the stdout to /dev/null and then stderr to what stdout is now, so also to /dev/null. It doesn't matter at all where the stdout and stderr pointed to just before >/dev/null 2>&1; this particular snippet does not depend on previous redirections.


Example: your workaround

Your workaround is:

(strace echo something 2>&1 >/dev/null) |& wc -l

which "expands" to:

(strace echo something 2>&1 >/dev/null) 2>&1 | wc -l

and the first part is like:

(strace echo something 2>&1 >/dev/null) >fifo 2>&1

Note it's different than >fifo 2>&1 >/dev/null 2>&1 we observed in the allegedly failing case.

For completeness let's analyze how (foo 2>&1 >/dev/null) >fifo 2>&1 works:

  1. First a subshell is created, its stdin gets redirected to the fifo (>fifo), its stderr gets redirected to the current stdout (the last 2>&1), so to the fifo as well.

  2. Then foo is about to run inside the subshell. Without further redirections it would inherit the standard descriptors from the subshell. This means the "default" stdout and stderr of foo both go to the fifo.

  3. Stderr of foo gets redirected to its current stdout (the first 2>&1). They are both the fifo, so this changes nothing. Then stdout of foo gets redirected to /dev/null (>/dev/null).

In effect stderr (but not stdout) of foo goes to the fifo, i.e. through the pipe.


Conclusions

The whole issue is not "redirection failing", it's not a bug. It's simply because |& turns into 2>&1 |, but then | acts before and 2>&1 acts after any explicit redirections you specify.

Do not consider |& as "| with extra functionality". When using it, think of an alias, a textual replacement: imagine |& will expand to 2>&1 | (as if you typed 2>&1 | instead of |&); then 2>&1 and | will do their respective jobs independently (as if |& was never a thing).