My guess is a permissions issue on the file from the linux user running the oracle database.
Thanks for replying. three items
1. The directory permissions are already 777 (forgot to mention that before).
2. If the directory permissions were to blame it wouldn't work from sql*plus.
3. I'm not sure how bouncing the database would consistently fix a file permissions issue.
Perhaps there is an explination somewhere about the user/privilege cascade from APEX through the database to the filesystem or perhaps a different internals issue with APEX seeing database directories pointing to nfs mounted filesystems? I assume this is something esoteric but there seem to be several "unaswered" posts about this issue so I know I'm not completely alone in needing a solution.
With regard to item 2, this is not correct. Unless you are actually connecting as the user APEX_PUBLIC_USER and then doing a SET SCHEMA to the parsing schema of the application, then you are not testing Apples-to-Apples with respect to underlying permissions when you connect via SQL*Plus. That said, if the permissions are wide open (777), then, agreed, this is likely not your problem.
My guess, and one that would be explain being fixed by a DB bounce, is a file locking issue.
However, you can get more information about exactly what it is that UTL_FILE doesn't like by adding a more verbose EXCEPTION handler. Here is an example:
WHEN UTL_FILE.INVALID_PATH THEN
RAISE_APPLICATION_ERROR( -20002, 'Invalid Path Specified' ); RAISE;
WHEN UTL_FILE.INVALID_MODE THEN
RAISE_APPLICATION_ERROR( -20003, 'Invalid Mode Specified' ); RAISE;
WHEN UTL_FILE.INVALID_FILEHANDLE THEN
RAISE_APPLICATION_ERROR( -20004, 'Invalid File Handle' ); RAISE;
WHEN UTL_FILE.INVALID_OPERATION THEN
RAISE_APPLICATION_ERROR( -20005, 'Invalid Operation Specified' ); RAISE;
WHEN UTL_FILE.READ_ERROR THEN
RAISE_APPLICATION_ERROR( -20006, 'Unable to Read Specified File' ); RAISE;
WHEN UTL_FILE.WRITE_ERROR THEN
RAISE_APPLICATION_ERROR( -20007, 'Unable to Write to Specified File' ); RAISE;
WHEN UTL_FILE.INTERNAL_ERROR THEN
RAISE_APPLICATION_ERROR( -20008, 'Unspecified Internal Error Encountered' ); RAISE;
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR( -20009, 'Operation Read Past End of File' ); RAISE;
WHEN VALUE_ERROR THEN
RAISE_APPLICATION_ERROR( -20010, 'Invalid Value Encountered. Perhaps ' ||
'an argument to a GET or PUT operation ' ||
'was > 1022 Bytes' ); RAISE;
I was going to make similar comment about #2 - OS user will be different.