Globbing
du -hs * in your code contains bare * globbing pattern. Your shell expands it to filenames of almost all files in the current directory, so in general du gets multiple arguments: directories and non-directories.
"Almost", because * doesn't match names starting with a dot (.). These are hidden. In Bash you can change this behavior by invoking shopt -s dotglob.
To match directories only, append a trailing slash to the pattern:
du -hs */ | sort -rh | head -10
This simple solution will fail if there are too many directories. The error will be argument list too long.
find
A generic way to do something to files matching some criteria is find. A find command solving your case is more complicated than the above. I'm posting it here mainly as a starting point for users who want to add more criteria (especially criteria that cannot be easily included in the solution with */):
find . -type d ! -name . -prune -exec du -hs {} + | sort -rh | head -10
It means: starting from . find all files of the type directory (-type d) that are not . (! -name .). Do not descend into them (-prune). Execute du -hs zero or more times, passing possibly multiple pathnames of found files to a single invocation of du (-exec du … {} +).
This solution won't trigger argument list too long because find is smart enough to run more than one du, if needed, so each du gets a list that is not too long. If you need a robust solution (e.g. in a script that should work without supervision) then prefer find over globbing.
ncdu
An interactive approach is ncdu. It's true it shows non-directories along with directories, but you can easily tell them apart (observe leading slashes) or toggle "dirs before [other] files when sorting" (t).