There is a space before the shebang in your script - which breaks the file magic:
$ printf '#!/bin/bash\n' | file -
/dev/stdin: Bourne-Again shell script, ASCII text executable
but
$ printf ' #!/bin/bash\n' | file -
/dev/stdin: ASCII text
This causes the XDG autostart mechanism to fall back to executing the script with /bin/sh, in which say-stuff isn't a valid function name:
$ sh -c 'say-stuff () { echo "stuff"; }'
sh: 1: Syntax error: Bad function name
You can see this happening if you run xdg-autostart in an interactive terminal with a minimal .desktop file:
$ cat ~/.config/autostart/say-stuff.desktop
[Desktop Entry]
Type=Application
Name=say-stuff
Exec=say-stuff
then
$ xdg-autostart 2>&1 | grep -A3 say-stuff
** Message: 18:23:33.620: xdg-autostart.vala:39: Processing /home/steeldriver/.config/autostart/say-stuff.desktop file.
** Message: 18:23:33.627: xdg-autostart.vala:94: Launching: say-stuff (say-stuff.desktop)
** Message: 18:23:33.627: xdg-autostart.vala:39: Processing /etc/xdg/autostart/nm-tray-autostart.desktop file.
/home/steeldriver/.local/bin/say-stuff: 3: Syntax error: Bad function name
** Message: 18:23:33.646: xdg-autostart.vala:94: Launching: nm-tray (nm-tray-autostart.desktop)
** Message: 18:23:33.646: xdg-autostart.vala:39: Processing /etc/xdg/autostart/upg-notifier-autostart.desktop file.
** Message: 18:23:33.655: xdg-autostart.vala:94: Launching: /usr/libexec/lubuntu-update-notifier/lubuntu-upg-notifier.sh (upg-notifier-autostart.desktop)
It "works" when you execute the script directly because
say-stuff is a legal function name in bash; and
your interactive shell is bash, and that causes the script with the invalid shebang to also run in bash
See also Which shell interpreter runs a script with no shebang?