Summary
NC4_create_file reports every H5Fcreate failure as the POSIX errno EACCES (13), so nc_strerror renders any netCDF-4 create failure as "Permission denied" — whatever actually went wrong. Two consequences:
- The diagnosis is usually wrong, and it points users at file permissions, which are usually fine.
- A positive POSIX errno is returned where the API documents netCDF status codes (
NC_NOERR or negative NC_E*). nc_strerror only produces a sensible string here by falling through to strerror.
libhdf5/hdf5create.c on main (db5a7f9), both call sites:
if ((hdf5_info->hdfid = nc4_H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0)
BAIL(EACCES); /* line 244, diskless */
}
else /* Normal file */
{
/* Create the HDF5 file. */
if ((hdf5_info->hdfid = nc4_H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0)
BAIL(EACCES); /* line 250, normal */
}
The line immediately above the first one already does the conventional thing — if (H5Pset_fapl_core(...) < 0) BAIL(NC_EHDFERR); — so this looks like an oversight rather than a deliberate mapping.
Reproducer
Stock netCDF-C and HDF5, no plugins or drivers involved. The path's directory does not exist, so the real error is ENOENT:
#include <netcdf.h>
#include <stdio.h>
static void try_create(const char *p, int cmode, const char *label) {
int ncid, stat = nc_create(p, cmode, &ncid);
printf("%-10s nc_create(\"%s\") -> %d (%s)\n", label, p, stat, nc_strerror(stat));
if (!stat) nc_close(ncid);
}
int main(void) {
try_create("no_such_dir/x.nc", NC_NETCDF4, "netcdf-4");
try_create("no_such_dir/x.nc", 0, "classic");
return 0;
}
netcdf-4 nc_create("no_such_dir/x.nc") -> 13 (Permission denied)
classic nc_create("no_such_dir/x.nc") -> 2 (No such file or directory)
The classic dispatcher gets it right for the same path; only the netCDF-4 path claims a permission problem. And a genuine permission failure (creating in a chmod 555 directory) also returns 13, so the two are indistinguishable from the API.
How this cost real time
We hit it through a VFD, where nothing about the failure was permission-related: a CLIO VFD build rejected an HDF5_DRIVER_CONFIG string whose grammar had changed upstream, H5Fcreate failed, and the application reported
Sorry! Unexpected result, .../nc_perf/tst_chunks3.c, line: 314 - Permission denied
Only strace settled it — no syscall in the process ever returned EACCES, and the file was never even opened for writing. Any FAPL, VFD, VOL, or plugin-loading failure lands on these two lines, and HDF5 2.x makes it harder still: driver callbacks now run inside H5_BEFORE_USER_CB, so a driver's own pushed error does not reach the caller's stack and all the user sees is H5FD_open(): can't open file. With BAIL(EACCES) on top, netCDF-4 users get "Permission denied" for a config-string typo.
Suggested fix
Return NC_EHDFERR at both sites, matching the surrounding code — or map the HDF5 error stack to a netCDF status if a finer answer is wanted, but in any case not a bare positive errno. Happy to send a PR if you'd like it in this shape.
If the intent was to keep reporting a real EACCES distinctly, that could be done deliberately (e.g. access()/errno check on the parent directory) rather than by assuming every create failure is one.
Environment
- netCDF-C
main (tested at 984d9758, a local branch whose only delta is an unrelated MSVC build fix under nc_perf/; libhdf5/hdf5create.c is identical to main @ db5a7f93)
- HDF5
develop @ 562e6028 (2.3.0), shared, thread-safety off, zlib on
- x86-64 Linux (WSL2, glibc 2.39), gcc 13
Summary
NC4_create_filereports everyH5Fcreatefailure as the POSIX errnoEACCES(13), sonc_strerrorrenders any netCDF-4 create failure as "Permission denied" — whatever actually went wrong. Two consequences:NC_NOERRor negativeNC_E*).nc_strerroronly produces a sensible string here by falling through tostrerror.libhdf5/hdf5create.conmain(db5a7f9), both call sites:The line immediately above the first one already does the conventional thing —
if (H5Pset_fapl_core(...) < 0) BAIL(NC_EHDFERR);— so this looks like an oversight rather than a deliberate mapping.Reproducer
Stock netCDF-C and HDF5, no plugins or drivers involved. The path's directory does not exist, so the real error is
ENOENT:The classic dispatcher gets it right for the same path; only the netCDF-4 path claims a permission problem. And a genuine permission failure (creating in a
chmod 555directory) also returns 13, so the two are indistinguishable from the API.How this cost real time
We hit it through a VFD, where nothing about the failure was permission-related: a CLIO VFD build rejected an
HDF5_DRIVER_CONFIGstring whose grammar had changed upstream,H5Fcreatefailed, and the application reportedOnly
stracesettled it — no syscall in the process ever returnedEACCES, and the file was never even opened for writing. Any FAPL, VFD, VOL, or plugin-loading failure lands on these two lines, and HDF5 2.x makes it harder still: driver callbacks now run insideH5_BEFORE_USER_CB, so a driver's own pushed error does not reach the caller's stack and all the user sees isH5FD_open(): can't open file. WithBAIL(EACCES)on top, netCDF-4 users get "Permission denied" for a config-string typo.Suggested fix
Return
NC_EHDFERRat both sites, matching the surrounding code — or map the HDF5 error stack to a netCDF status if a finer answer is wanted, but in any case not a bare positive errno. Happy to send a PR if you'd like it in this shape.If the intent was to keep reporting a real
EACCESdistinctly, that could be done deliberately (e.g.access()/errnocheck on the parent directory) rather than by assuming every create failure is one.Environment
main(tested at984d9758, a local branch whose only delta is an unrelated MSVC build fix undernc_perf/;libhdf5/hdf5create.cis identical tomain@db5a7f93)develop@562e6028(2.3.0), shared, thread-safety off, zlib on