In your code with set -e (short for set -o errexit) unhandled command failures cause the shell to exit.
pidof returns with a failure exit status when no matching process is found, but you do handle that failure. pidof is used as part of a and-or list, so its failure does not trigger errexit.
However because you used an and-or list where you should have used a if construct, the pidof && othercommand itself exits with a non-zero exit status and because that and-or list is the last thing run in the checkIfRunning function, the checkIfRunning function itself will also return with a failure exit status.
And that failure is not handled, so errexit is triggered. errexit is triggered not because pidof fails but because checkIfRunning failed.
Here, you should have written:
checkIfRunning() {
if pidof -o %PPID -x -- "$0" >/dev/null; then
echo >&2 'Already running!'
exit 1
fi
}
The exit status of a if construct is that of the last command run in the then or else part or 0 if none was run, not the exit status of the condition part.
Generally, replacing if constructs with and-or lists is wrong. Besides the problem of the overall exit status, if echo fails in your pidof && echo && exit 1, the script doesn't exit.
I'd argue that as soon as you use functions or anything other than the simplest script, errexit should be avoided and proper error handling be done.
See the corresponding section about set -euo pipefail in the bash wiki (short for set -o errexit -o nounset -o pipefail) or this FAQ entry.
Regarding your (now deleted) answer which tried to address the problem with:
checkIfRunning() {
set +e # <---
pidof -o %PPID -x $0 >/dev/null \
&& echo "running!" && exit 1
set -e # <---
}
The only reason it works is because set -e happens to exit with a success status, so checkIfRunning does as well, the set +e is irrelevant and not needed, set -e could have been replaced with true or return 0.