Note that as @muru commented, that's not a syntax error as far as Dash is concerned. [ is not a special character to the shell in the way ; and ( are. [ is just a regular command like echo, only with a funny name. In Bash/Ksh/Zsh [[ is a keyword like if, and keywords are part of the shell syntax, but crucially, in shells that don't support it, [[ would be treated as just another command.
Since Dash doesn't support [[, it's looked for in the PATH as any other command, and the lookup fails. As the answer by Arkadiusz Drabczyk says, the result here is an exit status of zero. If it was an actual syntax error, the shell would exit immediately with a non-zero status.
How can I detect this kind of error in a script if I can't rely on the exit code?
Well, technically, you could...
#!/bin/dash
[[ $1 == "foo" ]]
case $? in
0) echo "the first argument was 'foo'";;
1) echo "the first argument was something else";;
127) echo "[[ not supported";;
*) echo "there was some other error";;
esac
Or the same with ret=$? and a chain of if-elif with conditions against $ret. That's somewhat awkward to do, and not the best solution here, but if you really need to tell apart different error codes of some command, that's what you have to do.
If you're aiming at detecting the Dash vs. Bash case in particular, you could add an extra test at the start of the script to see if [[ works correctly:
#!/bin/bash
if ! [[ a == a ]] 2>/dev/null; then
echo "[[ not supported, exiting." >&2
exit 1
fi
# ...
Similarly, you could probably add tests for all other non-POSIX features you use, but testing them all can of course get a bit unwieldy.
To demand exactly Bash, and not just any shell that has the same features (Ksh and Zsh are compatible with some stuff, though not with all), check $BASH_VERSION at the start of the script:
#!/bin/bash
if [ -z "$BASH_VERSION" ]; then
echo "Running only with Bash supported, exiting" >&2
exit 1
fi
# ...
(The variable can of course be set manually, but than the user better know what they're doing.)