I cannot say for sure but usually when you can do something in an anonymous block but not in a stored program unit it is due to privileges granted by role rather than directly (roles are disabled in stored PL/SQL by default).
Is there a way I can validate that? If stored PL/SQL can access that directory or not ?
Sorry for delay.
One quick check is to use SET ROLE NONE and try the anonymous block again. If the anonymous block subsequently fails the privilege is granted via a role rather than directly.
Directory privileges (READ/WRITE) are visible in USER/ALL/DBA_TAB_PRIVS views.