A more intuitive solution would be to resolve globs to nothing (the empty string) if they don't match. In most users' mental models "*.jpg" means "any file ending with .jpg" when they pass it to a command like "rm" or "mv", but in reality it means "any file ending with .jpg in the current directory, or the literal string '*.jpg' if there are none" which is nonsensical. If it expanded to nothing, it would be obvious that it needs escaping when passed to commands like find because find would complain about not being passed a file name. The failure case is outright user-hostile and error-prone.
Also if every tool used its own metacharacters, users would have to re-learn them for every tool. It's common for config files to also use globs, for example. Even if we just had one set of characters for shells and one set for other tools, it's often difficult to draw the line, especially if tools use shells and thus would need to translate from one set to another. If this is a design error in find, it's a design error in all tooling that isn't a shell and we need to throw it all out and start from scratch.
~ echo f43f3f*gsdgds
zsh: no matches found: f43f3f*gsdgds
~ bash
user@debian:~$ echo f43f3f*gsdgds
f43f3f*gsdgds> failglob
> If set, patterns which fail to match filenames during filename expansion result in an expansion error.
> nullglob
> If set, Bash allows filename patterns which match no files to expand to a null string, rather than themselves.
[1] https://www.gnu.org/software/bash/manual/bash.html#The-Shopt...
I agree, so I use shopt -s nullglob in both bash scripts and interactive shells. It retrained my interactive habits with find very quickly because unquoted wildcards no longer work in the common case where there's no match in the current directory.
(I like dotglob, extglob, globstar and pipefail everywhere too: saner defaults than emulating traditional shell behaviours.)
The issue with find here is that globs act consistently, but the returned behaviour is dependent on when the evaluation is performed.
find(1) treats * just as the shell does, but only if the shell hasn't got to the * first. So to prevent the shell from pattern-matching any * characters, you've got to quote or escape them using single quotes (') or backstrokes (\).
Quoting to prevent interpretation of metacharacters is actually commonly encountered in computer contexts. I'm having to quote instances of * but not \ for example in this comment to HN as both have semantic meaning to the content parser. Note that the escape character '\' is only significant when used immediately preceding a *.
I don't disagree with your central point that this problem can be fixed with better design. But the ergonomics are a hard problem to solve.