Informix Error -33
-33 Argument too large.
An operating-system error code with the meaning shown was unexpectedly returned to the database server. If the error recurs, note all circumstances and contact IBM Informix Technical Support.
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.
Important platform note. Error codes in this range represent operating-system
errnovalues whose meanings vary between Unix platforms and versions. Confirm the nativeerrnodefinition on the server where the Informix error occurred before diagnosing the problem from the number alone.
Determine the Native Error Meaning
Errno 33 is EDOM on Linux, Solaris, AIX, HP-UX and the BSD-derived systems. It is one of the stable values in this range, and the stability extends exactly this far:
| Code | Linux | Solaris / AIX / HP-UX | BSD-derived |
|---|---|---|---|
| -33 | EDOM |
EDOM |
EDOM |
| -34 | ERANGE |
ERANGE |
ERANGE |
| -35 | EDEADLK |
ENOMSG |
EWOULDBLOCK |
| -36 | ENAMETOOLONG |
EIDRM |
EINPROGRESS |
-33 and -34 are the last two codes on which every platform still agrees. From -35 onwards the three numbering families diverge completely and the static text Informix carries can only be right for one of them. (Informix's own table reads "Operation would block" at -35 and "Operation now in progress" at -36, which is the BSD lineage — so on Linux and on the System V platforms that text is describing a different error entirely from -35 onward.)
Verify on the host that logged the error regardless, and record the result:
python3 -c 'import os; print(os.strerror(33))'
perl -e '$! = 33; print "$!\n"'
grep -w 33 /usr/include/asm-generic/errno-base.h # Linux
grep -w 33 /usr/include/sys/errno.h # Solaris, AIX, HP-UX
Note also that the official text for this code — Argument too large — does not match any platform's own wording for EDOM, which is some variation on argument out of domain. "Too large" suggests a magnitude problem, and EDOM is not about magnitude; -34 ERANGE is the one concerned with a result being too large to represent. Read the symbol, not the sentence.
Everything below assumes the check returned EDOM.
What EDOM Actually Tells You
EDOM means a mathematical function was given an argument outside its domain — a value for which the function has no defined result:
| Call | Domain error when |
|---|---|
sqrt(x) |
x < 0 |
log(x), log10(x), log2(x) |
x < 0 (and x == 0 is a range error, giving ERANGE) |
asin(x), acos(x) |
|x| > 1 |
pow(x, y) |
x < 0 and y not an integer |
fmod(x, y), remainder(x, y) |
y == 0 |
acosh(x) |
x < 1 |
atanh(x) |
|x| > 1 |
EDOM is set by the C math library, not by the kernel. No system call returns it. open(), read(), write(), stat(), fork() and every other operation the database server performs against the operating system have no path that produces errno 33.
That matters because the Informix -1 to -99 range exists to report errno values that came back from operating-system calls. A value that the operating system cannot produce in that context has arrived by some other route — and identifying which route is the real diagnostic work on this error.
What This Means in Informix
A -33 is rare, and in most cases it is not reporting a genuine domain error at all. There are three explanations, and they are worth taking in order of likelihood rather than in order of plausibility.
1. A stale errno — the most likely explanation
errno is a global that is only meaningful immediately after a call that has indicated failure. It is never cleared on success. Code that inspects errno after a call that succeeded, or after a call that failed without setting it, reads whatever value was left there by something earlier — possibly much earlier, possibly in an unrelated library.
A value from the math-library range is a strong tell for exactly this, because nothing in the calling path that logged the error could have produced it legitimately.
So on a -33, the first question is not "what argument was out of domain?" It is "is this number being reported by something that had no business reading errno at that point?" Look at what the engine was doing when it logged the error — if the operation was file, memory, process or network work, the number is almost certainly residue.
2. A C UDR or DataBlade module that called libm
This is the one route to a genuine EDOM in an Informix context, and it is a real one. A user-defined routine written in C that calls sqrt(), log(), pow(), asin() or fmod() on column data will set errno to 33 the moment a row arrives with a value outside the function's domain — a negative number reaching sqrt(), a zero reaching fmod()'s divisor, a ratio slightly over 1.0 reaching acos() through accumulated floating-point error.
Two things then go wrong, and they compound:
- The UDR may return the errno to the server as though it were a system error, which is how a math-library value reaches a range reserved for operating-system errors.
- The UDR may leave
errnoset and return normally, so that some later, entirely unrelated check in the server reads 33 and reports it. This is the manufacturing process for explanation 1 above.
The failure is data-dependent, which is why it surfaces as an intermittent error against a routine that has worked for years: it needs one row with the wrong value, and that row may have been loaded last night.
3. The platform's errno 33 is not EDOM
Unlikely given the agreement across platforms, but it costs one command to eliminate and it is the check this whole class of errors exists to enforce.
Why built-in SQL arithmetic rarely shows up here
Out-of-domain arithmetic in the server's built-in SQL functions raises a SQL-level error, and that error will generally mask the underlying errno — the statement fails with something that names the SQL problem, and the operating-system number never reaches you.
Two things follow.
First, a bare -33 arriving alongside a statement doing square roots or logarithms points at a user-defined routine in the execution path rather than at a built-in function. Not because the built-in cannot set errno — it may well — but because you would normally be reading a SQL error instead. That usefully narrows where to look.
Second, and less obviously: masking does not mean clearing. An errno that was set underneath a SQL error is still sitting in the global afterwards, and the next piece of code to read errno without having checked a failure of its own will find 33 there. That is the manufacturing process for explanation 1 above, and it is why a domain error that was correctly handled at the SQL layer can still produce a misleading number somewhere else entirely.
Common Causes
- A stale
errnoread after a call that did not set it — the most common explanation, and not a domain error at all. - A C UDR or DataBlade routine calling a math function on data outside its domain: a negative value into
sqrt()orlog(), a zero divisor intofmod(), a value marginally outside ±1 intoasin()oracos(). - A UDR that does not clear
errnobefore a math call, and so reports a value left over from an earlier operation. - Floating-point drift pushing a computed ratio just outside a valid range — a classic source of
acos()domain errors, where the mathematics guarantees|x| <= 1and the arithmetic does not. - A newly loaded or newly migrated dataset containing values the routine has never previously been given.
- An external program in a backup, alarm or load pipeline whose exit status or errno is captured and propagated without regard for whether it was meaningful.
Diagnostic Checks
Confirm the symbol first, as above — this is the check the class exists for:
python3 -c 'import os; print(os.strerror(33))'
Then establish what the engine was doing. On this error that context is the diagnosis, because it tells you immediately whether 33 could be genuine:
tail -300 "$INFORMIXDIR/tmp/online.log"
onstat -m
grep -n -iE 'errno|system error|ISAM|UDR|routine' "$INFORMIXDIR/tmp/online.log" | tail -40
If the surrounding entries describe file, network, memory or process work, stop treating it as a domain error — no such operation produces errno 33, and you are looking at a residual value.
Find the user-defined routines in the picture. A genuine EDOM needs C code that called libm:
SELECT procname, numargs, externalname
FROM sysprocedures
WHERE externalname IS NOT NULL
AND langid <> 1;
See which modules the virtual processors have actually loaded. This is a shorter and more truthful list than the catalogue — sysprocedures tells you what is registered, onstat -g dll tells you what is loaded:
onstat -g dll
Datablades:
addr slot vp baseaddr flags filename
140090fc 2 1 fe64d4e0 PM /informix/extend/risk.1.00/risk.bld
141c70fc 2 fe7cd4e0
141ca0fc 3 fe7cd4e0
The listing is per virtual processor. A module loaded into several CPU VPs appears once per VP, with the slot number shown only on the first line and the remaining lines carrying the same module at a different baseaddr. So the row count tells you how widely the module is loaded, not how many modules there are.
The flags are worth reading. P means the library was loaded at server startup rather than on first use; M means a thread calling into it may migrate between CPU virtual processors. A module carrying M is one whose routines are not pinned to a single VP, which matters if you are trying to correlate an error against a particular processor.
The filename column gives you the path for the next two commands. A module that does not appear at all cannot have contributed to this error.
Oninit®'s own reference for this option, with the full column descriptions, is at onstat -g dll.
Check whether those objects link the math library:
ldd /informix/extend/<module>/<module>.so | grep -i libm
nm -D /informix/extend/<module>/<module>.so | grep -iE ' U (sqrt|log|pow|asin|acos|fmod|atanh|acosh)'
nm -D listing undefined math symbols confirms the routine can produce this error. An object that does not reference libm at all rules itself out in one command.
Look for the data, once you know which routine and which column:
-- adjust to the routine's actual argument
SELECT COUNT(*) FROM <table> WHERE <col> < 0; -- sqrt, log
SELECT COUNT(*) FROM <table> WHERE <col> = 0; -- fmod divisor
SELECT COUNT(*) FROM <table> WHERE ABS(<col>) > 1; -- asin, acos
Check when the data changed, because a routine that has worked for years failing today is a data event rather than a code event:
grep -iE 'load|insert|import|LOAD FROM' /path/to/job/logs | tail
Establish which error mechanism the platform's libm uses, if you are working on the C code:
printf '#include <math.h>\n#include <stdio.h>\nint main(void){printf("%%d\\n", math_errhandling);}\n' \
> /tmp/meh.c && cc /tmp/meh.c -lm -o /tmp/meh && /tmp/meh
A result with bit 1 (MATH_ERRNO) set means errno is used; bit 2 (MATH_ERREXCEPT) means floating-point exception flags are used. Many modern platforms set both, and some set only the latter — in which case checking errno after a math call is unreliable in a different way again.
Solutions / Resolution
- Confirm the symbol, then confirm the context. If the operation that logged the error was not arithmetic, treat the number as residue and pursue the actual failure — which will be recorded near it — rather than the errno.
- Do not chase a domain error that nothing in the picture could have produced. Time spent on
sqrt()when the failing operation was a file open is time taken from the real fault. - In a C UDR, validate before you calculate. Test the argument against the function's domain and return a defined result or a proper SQL error, rather than calling the function and inspecting the aftermath. A negative value reaching
sqrt()is a data condition the routine should express, not an operating-system error to propagate. - Clamp values that floating-point drift pushes outside a range. Where the mathematics guarantees
|x| <= 1and the arithmetic does not, clamp to the boundary before callingacos()orasin(). This is standard practice in numerical code and removes an entire class of intermittent failure. - Set
errno = 0before any math call you intend to check, and check it immediately afterwards. Math functions return a value rather than a failure indication, soerrnois the only signal — and an unclearederrnomakes it meaningless. - Never return a libm
errnoto the server as a system error. It is not one, and doing so puts a value into a range reserved for operating-system errors where the next person to read it will be misled exactly as you were. - Restore
errnodiscipline in the UDR generally. A routine that leaveserrnoset on a normal return is a source of misleading errors elsewhere in the server, and those will not be attributed to it. - If the data is wrong, fix the data. A negative value in a column that a routine assumes is non-negative is usually a constraint that was never written.
C UDRs run inside the server's own virtual processors and are subject to constraints that do not apply to ordinary application code — around signals, process creation, file descriptors and memory duration in particular. Review those before changing a routine.
Examples
The number cannot mean what it says
... system error = 33
logged beside entries describing a file operation. Errno 33 is EDOM, set only by the math library; no file operation can produce it. The value is left over from something earlier in the same thread, and the operation that actually failed is described in the surrounding lines rather than in the number.
This is the common shape of a -33, and recognising it in the first minute saves the rest of the investigation.
A UDR that has worked for years
> SELECT customer_id, risk_index(exposure, variance) FROM positions;
risk_index is a C routine that takes a square root. It has run nightly since 2019. Last night's load included the first negative variance in the table's history — a sign error upstream — and sqrt() set errno to 33 on that row.
$ nm -D /informix/extend/risk/risk.so | grep -E ' U (sqrt|log|pow)'
U sqrt@GLIBC_2.2.5
> SELECT COUNT(*) FROM positions WHERE variance < 0;
(count(*))
1
One row. The routine should reject it explicitly rather than calling sqrt() and reporting what the math library made of it — and the column should have had a check constraint.
Floating-point drift into acos()
A geometric or correlation calculation where the value passed to acos() is mathematically guaranteed to lie within ±1, and arithmetically arrives as 1.0000000000000002:
/* before */
double angle = acos(dot / (len_a * len_b));
/* after */
double c = dot / (len_a * len_b);
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
double angle = acos(c);
The failure is intermittent, depends entirely on the data, and disappears the moment anyone tries to reproduce it with clean numbers. Clamping is the standard fix and costs nothing.
Platform Note
Errno 33 is EDOM on Linux, Solaris, AIX, HP-UX and the BSD-derived systems. Unusually for this range, the symbol is portable.
What is not portable is how a math error is signalled at all. C99 gives implementations a choice between setting errno and raising floating-point exception flags, and math_errhandling reports which. Code written on a platform that sets errno and moved to one that raises flags — or built with optimisation settings that permit the compiler to assume neither matters — will silently stop detecting the condition it was written to catch.
| Task | Linux | Solaris | AIX |
|---|---|---|---|
| errno text | strerror, perl -e '$!=33' |
same | same |
| Math symbols in an object | nm -D, ldd |
nm -D, ldd |
dump -Tv, ldd |
| Math error mode | math_errhandling |
math_errhandling |
math_errhandling |
This is also the boundary code for the range. -33 and -34 mean the same thing everywhere; -35 onwards do not, and any runbook that reads an errno number out of a table without naming the platform stops being correct at that point.
Related Errors / Related Topics
- -34 —
ERANGE, the sibling condition. The argument was in the function's domain but the result is not representable:exp()of a large value,log(0), an underflow to zero. Where -33 is "you cannot ask that", -34 is "the answer will not fit". These two are frequently confused, and Informix's own text for -33 — Argument too large — reads more like -34 than like a domain error. - -22 —
EINVAL, Invalid argument. The kernel's equivalent judgement, and the error a genuine bad-argument condition from a system call produces. If you are looking for "something was passed a value it would not accept", -22 is far more likely to be the real one. - -35 — the first code in this range where the platforms disagree, and the reason every page here begins by asking you to confirm the symbol.
Where a -33 appears without a user-defined routine anywhere in the execution path, treat the number as untrustworthy rather than as evidence. The useful record is the operation the server was performing, which is in the message log beside it.