DEV Community

umzzil nng
umzzil nng

Posted on • Originally published at oraerror.com

PostgreSQL 2201E Error: Causes and Solutions Complete Guide

PostgreSQL Error 2201E: invalid argument for logarithm

PostgreSQL error code 2201E (invalid_argument_for_logarithm) is thrown when you pass a zero or negative number to a logarithmic function such as log() or ln(). Mathematically, logarithms are only defined for positive real numbers, so the database engine raises this error to enforce that mathematical constraint. If you're hitting this error in production, it almost always means your data contains unexpected zero or negative values that weren't caught before the calculation.


Top 3 Causes

1. Passing Zero or Negative Values Directly

The most common cause is simply having 0 or negative numbers in the column you're feeding into log() or ln().

-- This will throw 2201E if any sales_amount <= 0
SELECT log(sales_amount) FROM sales;

-- Reproduce the error intentionally
SELECT log(0);   -- ERROR: invalid argument for logarithm
SELECT log(-5);  -- ERROR: invalid argument for logarithm
SELECT ln(-1);   -- ERROR: invalid argument for logarithm
Enter fullscreen mode Exit fullscreen mode

2. NULL Replaced with Zero via COALESCE

Developers often use COALESCE to handle NULLs but accidentally replace them with 0, which then gets passed to log().

-- This looks safe but will cause 2201E when amount IS NULL
SELECT log(COALESCE(amount, 0)) FROM transactions;

-- NULL itself is fine — log(NULL) returns NULL without error
SELECT log(NULL);  -- Returns: NULL (no error)
Enter fullscreen mode Exit fullscreen mode

3. Unvalidated Data from ETL or External Sources

When data flows in from external systems or ETL pipelines without range validation, rogue zero or negative values can silently enter your tables and blow up downstream log calculations.

-- Check for problematic values before processing
SELECT
    COUNT(*) FILTER (WHERE value <= 0) AS invalid_count,
    COUNT(*) FILTER (WHERE value IS NULL) AS null_count,
    COUNT(*) FILTER (WHERE value > 0)  AS valid_count
FROM source_data;
Enter fullscreen mode Exit fullscreen mode

Quick Fix Solutions

Use CASE WHEN or NULLIF to guard your log calls:

-- Safe pattern using CASE WHEN
SELECT
    id,
    CASE
        WHEN sales_amount > 0 THEN log(sales_amount)
        ELSE NULL
    END AS log_sales
FROM sales;

-- Safe pattern using WHERE filter
SELECT id, log(value)
FROM measurements
WHERE value > 0;

-- Fix the COALESCE-zero anti-pattern
-- Instead of log(COALESCE(amount, 0)), use:
SELECT log(NULLIF(COALESCE(amount, 1), 0)) FROM transactions;

-- Create a reusable safe_log function
CREATE OR REPLACE FUNCTION safe_log(p_value NUMERIC)
RETURNS NUMERIC AS $$
    SELECT CASE WHEN p_value > 0 THEN log(p_value) ELSE NULL END;
$$ LANGUAGE sql IMMUTABLE;

-- Now use it anywhere without worrying about 2201E
SELECT safe_log(sales_amount) FROM sales;
Enter fullscreen mode Exit fullscreen mode

Prevention Tips

1. Add a CHECK constraint at the table level

Stop bad data at the source by enforcing positivity directly on the column.

-- At table creation
CREATE TABLE sensor_readings (
    id SERIAL PRIMARY KEY,
    reading NUMERIC NOT NULL,
    CONSTRAINT chk_positive_reading CHECK (reading > 0)
);

-- On an existing table
ALTER TABLE sales
ADD CONSTRAINT chk_positive_amount CHECK (sales_amount > 0);
Enter fullscreen mode Exit fullscreen mode

2. Validate data before log-heavy ETL steps

Build a pre-flight check into your pipeline that aborts or quarantines bad rows before any logarithmic transformation runs.

-- Quarantine invalid rows
INSERT INTO invalid_data_log (source_table, row_id, bad_value, detected_at)
SELECT 'source_data', id, value, NOW()
FROM source_data
WHERE value <= 0 OR value IS NULL;

-- Only process clean rows
INSERT INTO processed_results (id, log_value)
SELECT id, log(value)
FROM source_data
WHERE value > 0;
Enter fullscreen mode Exit fullscreen mode

Related Errors

Code Name Description
2201F invalid_argument_for_power_function Raised by power() with invalid base/exponent
22012 division_by_zero Similar domain-violation class for division
22003 numeric_value_out_of_range Result exceeds the numeric type's range

The key takeaway: never trust input data. Always guard logarithmic functions with a positivity check, and push that validation as far upstream as possible — ideally into a CHECK constraint on the table itself.


📖 Want a more detailed guide?
Check out the full in-depth version (Korean) on oraerror.com — includes detailed analysis, additional SQL examples, and prevention tips.

Top comments (0)