Here is a patch that updates the documentation of the ERR_EXIT and ERR_RETURN options. The main improvement is to better explain when these options are ignored.

As it may be a bit difficult to read it directly in the patch, I reproduced below the updated documentation:

ERR_EXIT
 
If a command has a non-zero exit status, execute the tt(ZERR)
trap, if set, and exit.

The option is ignored when executing the commands following tt(while),
tt(until), tt(if), or tt(elif), a pipeline beginning with tt(!), or
any command other than the last in command list containing tt(&&) or
tt(||).  Hence neither `tt(if foo; then true; fi)', nor `tt(foo &&
true)' trigger exit when tt(foo) returns with a non-zero exit status.
Note that if tt(foo) is a function, the option is also ignored during
its whole execution.

The option is also ignored when executing a complex command (tt(if),
tt(for), tt(while), tt(until), tt(repeat), tt(case), tt(select),
tt(always), or a list in braces) if its exit status comes from a
command executed while the option is ignored. Hence, the tt(if)
command in `tt(if true; then false && true; fi)' does not trigger
exit.

Finally, the option is also ignored while running initialization
scripts and inside tt(DEBUG) traps.  In the latter case, the option is
handled specially: it is unset on entry to the trap.  If the option
tt(DEBUG_BEFORE_CMD) is set, as it is by default, and the option
tt(ERR_EXIT) is found to have been set on exit, then the command for
which the tt(DEBUG) trap is being executed is skipped.  The option is
restored after the trap exits.

Exiting due to tt(ERR_EXIT) has certain interactions with asynchronous
jobs noted in
ifzman(the section JOBS in zmanref(zshmisc))\
ifnzman(noderef(Jobs & Signals)).

Note this behaviour is not disabled in interactive shells ---
a non-zero status on the command line causes the shell to exit.

ERR_RETURN

If a command has a non-zero exit status, return immediately from the
enclosing function.  Except for the exceptions described below, the
logic is the same as that for tt(ERR_EXIT), except that an implicit
tt(return) statement is executed instead of an tt(exit).  This will
trigger an exit at the outermost level of a non-interactive script.
At the top level of an interactive shell, it will trigger a return to
the command prompt; in other words, the sequence of commands typed by
the user may be thought of as a function for this purpose.

Unlike for tt(ERR_EXIT), when a function is called while the option is
being ignored, the option is NOT ignored during the execution of the
function.  Hence, if tt(foo) in `tt(foo && true)' is a function, code
inside it is considered separately: it may force a return from tt(foo)
(assuming the option remains set within tt(foo)).

Like for tt(ERR_EXIT), the option is ignored inside tt(DEBUG) traps
but it's not unset on entry to the trap and setting or unsetting it
inside the trap has no special effect.

If tt(ERR_RETURN) and tt(ERR_EXIT) are both set, the latter takes
precedence. Hence, exit rather than return is triggered when a command
has a non-zero exit status.

Philippe