Informix Error -20
-20 Not a directory.
An operating-system error code with the meaning shown was unexpectedly returned to the database server. Look for other operating-system error messages that might give more information. Some database servers store databases as directories that are named database.dbs. If you place a file (not a directory) with the .dbs suffix in your DBPATH, this error might result.
Oninit® Troubleshooting Guidance
This is an operating-system error number, not an Informix diagnosis.
The same errno is returned by many different operations, so on its own it says what the operating system refused, not what Informix was trying to do. Informix will usually have reported a more specific error alongside it — in the message log, in the SQL or ISAM error pair, or in the accompanying assert failure — and that error normally defines the real cause far more precisely than the errno does. Find it before diagnosing from this number alone.
This matters less than it used to. Later versions of the engine trap many of these conditions and report them as specific Informix errors naming the operation, the object and the context, so a bare errno in this range is increasingly a sign of an older version, an unusual code path, or a failure early in startup before the better reporting is available. If you are seeing one on a current version, the more specific error is worth looking for even harder.
Operating-System Meaning
errno 20 is ENOTDIR — Not a directory. Somewhere in a path, a component that had to be a directory is not one.
The critical word is somewhere. This is not necessarily about the final element:
/informix/backups/archive/log_0001
^^^^^^^
if this is a regular file, the whole path fails with ENOTDIR
however correct the rest of it looks
That makes it a close relative of -2 (ENOENT), and the two are separated the same way: by walking the path rather than examining the target. A component that does not exist gives -2; a component that exists but is a file where a directory was needed gives -20.
-21 (EISDIR) is the exact mirror of this error: a directory found where a file was expected. The two often appear in the same estate for the same reason — something recreated an object as the wrong type.
What This Means in Informix
DBPATH containing a file
The official text points directly at this, and it is worth following. DBPATH is a list of places to search, and every element of it that is a pathname must be a directory. A file sitting in that list causes the search to fail with -20 as soon as it is reached — including a file that looks entirely plausible.
The specific case the official text describes belongs to the older Standard Engine lineage, where a database was stored as a directory named dbname.dbs containing the tables as files. In that layout, a file named something.dbs in a DBPATH directory is exactly the trap: it has the right name and the wrong type.
Estates still running SE or holding archived SE data will meet this directly. On a modern server the same failure arises from the more general form — a DBPATH element that is a file rather than a directory.
Elsewhere
- A path component in a chunk path that is a regular file
DUMPDIR, a backup staging directory, or an unload target that is a file rather than a directory$INFORMIXDIRor$INFORMIXSQLHOSTSwhere an intermediate component has been replaced- A restore or a copy that recreated a directory as a file —
scpof a directory without-r, anrsyncthat flattened something, or an archive extracted with the wrong options - A symlink resolving to a file where the configuration expects it to resolve to a directory
Common Causes
- A
DBPATHelement that is a file, including the.dbscase above. - A path component replaced by a file, usually by a restore, copy or extract that went wrong.
- A configuration naming a file where a directory is required — staging areas and dump directories are the usual ones.
- A symlink pointing at a file where a directory was intended.
- A truncated or partial copy that created a file with a directory's name.
Diagnostic Checks
namei -l walks the whole path and shows the type of every component. On this error that is nearly always the entire diagnosis:
namei -l /path/to/target
ls -ld /path/to/target
stat -c '%F %n' /path/to/target
$ namei -l /informix/backups/archive/log_0001
f: /informix/backups/archive/log_0001
drwxr-xr-x root root /
drwxr-xr-x informix informix informix
drwxrwx--- informix informix backups
-rw-rw---- informix informix archive <- a file, used as a directory
log_0001 - Not a directory
Check every element of DBPATH explicitly, since the failing one is often not the one being thought about:
echo "DBPATH=[$DBPATH]"
printf '%s\n' "$DBPATH" | tr ':' '\n' | while read -r d; do
case "$d" in
//*) printf '%-40s %s\n' "$d" "server entry" ;;
"") ;;
*) printf '%-40s %s\n' "$d" "$(stat -c '%F' "$d" 2>/dev/null || echo MISSING)" ;;
esac
done
Anything reporting regular file is the fault.
Look for objects with directory-like names that are files — the .dbs case and its modern equivalents:
find /path/to/dbpath/dir -maxdepth 1 -name '*.dbs' -type f -ls
find /path/to/dbpath/dir -maxdepth 1 -name '*.dbs' ! -type d
Check the Informix directory parameters:
grep -nE 'DUMPDIR|ROOTPATH|MSGPATH|CONSOLE' "$INFORMIXDIR/etc/$ONCONFIG"
for d in "$INFORMIXDIR" "$INFORMIXDIR/etc" "$INFORMIXDIR/tmp" "${DUMPDIR:-}"; do
[ -n "$d" ] && printf '%-40s %s\n' "$d" "$(stat -c '%F' "$d" 2>/dev/null || echo MISSING)"
done
Resolve symlinks before judging — the link and its target can differ in type:
readlink -f /path/to/target
stat -c '%F %n' "$(readlink -f /path/to/target)"
If the failure is inside a client or a script, the failing call names the path directly:
strace -f -e trace=open,openat,stat,chdir /path/to/program 2>&1 | grep ENOTDIR
Solutions / Resolution
- Run
namei -lon the full path. It names the offending component and its type in one line, and most investigations end there. - Fix the object, not the configuration, when a directory has been replaced by a file. Work out what created the file before removing it — it may be the only copy of something.
- Correct
DBPATHto list directories (or//servernameentries) only. A stray file in the list will keep breaking searches that have nothing to do with it. - For the
.dbscase, establish whether the file is a damaged remnant of an SE database directory or something unrelated that happens to carry the suffix. Do not delete it before that is clear. - Re-run failed copies properly —
scp -r,rsync -a, or an extract with directory entries preserved — rather than creating the directory by hand and moving on, since whatever was inside it is also missing. - Check symlink targets where a configuration uses them.
- Re-test the Informix operation afterwards, not just the path.
Examples
A DBPATH element that is a file
$ echo "$DBPATH"
/informix/databases:/informix/shared:/informix/legacy/sales.dbs
$ printf '%s\n' "$DBPATH" | tr ':' '\n' | while read -r d; do
> printf '%-40s %s\n' "$d" "$(stat -c '%F' "$d" 2>/dev/null || echo MISSING)"
> done
/informix/databases directory
/informix/shared directory
/informix/legacy/sales.dbs regular file
The third element carries the .dbs suffix of an SE database directory but is a regular file — most likely what survived when the directory was archived or partially restored. Every search that reaches that element fails, regardless of which database was being looked for.
A component in the middle of the path
$ namei -l /informix/backups/archive/log_0001
f: /informix/backups/archive/log_0001
drwxr-xr-x root root /
drwxr-xr-x ifxprod ifxprod informix
drwxrwx--- ifxprod ifxprod backups
-rw-rw---- ifxprod ifxprod archive
log_0001 - Not a directory
archive is a regular file. A backup script that expected to create a directory wrote a file of that name instead — probably a redirect that should have been a mkdir. Everything under it is unreachable, and the error names the leaf rather than the cause.
A directory flattened by a copy
$ ls -ld /informix/etc
-rw-r--r-- 1 ifxprod ifxprod 8241 Sep 9 14:02 /informix/etc
$ stat -c '%F' /informix/etc
regular file
An scp without -r produced a file where a directory should be. Creating the directory would clear this error and leave the real problem — everything that was inside it never arrived.
Platform Note
errno 20 is ENOTDIR on Linux, AIX, Solaris, HP-UX and the BSD-derived systems — stable, so the number is reliable, and the behaviour is a property of path resolution rather than a platform choice.
namei is Linux (util-linux). Elsewhere, walk the path manually or trace the failing call:
| Task | Linux | Solaris | AIX |
|---|---|---|---|
| Walk a path's components | namei -l |
manual ls -ld per level |
manual ls -ld per level |
| Type of an object | stat -c '%F' |
ls -ld, file |
istat, ls -ld |
| Trace the failing call | strace -e trace=file |
truss -t open,stat |
truss -t open,stat |
A short loop reproduces the useful part of namei anywhere:
p=/informix/backups/archive/log_0001
d=""
IFS=/ read -ra parts <<< "$p"
for c in "${parts[@]}"; do
[ -z "$c" ] && continue
d="$d/$c"
printf '%-45s %s\n' "$d" "$(stat -c '%F' "$d" 2>/dev/null || echo '-- stops here --')"
done
Related Errors / Related Topics
- -21 — Is a directory. The exact mirror: a directory where a file was expected. Both usually mean something recreated an object as the wrong type, and finding one is reason to look for the other.
- -2 — No such file or directory. The component is missing rather than the wrong type;
namei -ldistinguishes them immediately. - -13 — Permission denied, the third outcome of walking a path, where a directory exists and cannot be traversed.
- -15 — Block device required, the equivalent type mismatch for device paths.
Where -20 follows a restore, migration or bulk copy, the object that failed is rarely the only one affected. Check the whole tree that operation touched rather than repairing the single path in the error.