Skip to content

Error Handling & Safety

H3 PHP is designed to fail loudly and safely. Every method that can fail throws a typed H3Exception, every user input is validated before it reaches the C library, and grid operations are bounded so a bad request can't exhaust memory. This page covers all three.

H3Exception

All failures throw Foysal50x\H3\H3Exception, which extends PHP's Exception. Wrap calls that depend on external input in a try/catch:

use Foysal50x\H3\H3;
use Foysal50x\H3\H3Exception;
 
try {
    $h3 = new H3();
    $cell = $h3->latLngToCell(37.7749, -122.4194, 20);   // 20 is out of range
} catch (H3Exception $e) {
    echo $e->getMessage();         // descriptive message + error code
    echo $e->getH3ErrorCode();     // the underlying H3 error code
 
    if ($e->isInvalidResolution()) {
        echo 'Resolution must be between 0 and 15';
    }
}

Inspecting the error

H3Exception carries the underlying H3 error code and a few convenience predicates:

MethodReturnsMeaning
getMessage()stringFull message, including the description and code
getH3ErrorCode()intThe numeric H3 error code
getH3ErrorDescription()stringHuman-readable description of the code
isInvalidCell()boolThe cell argument was not valid (code 5)
isInvalidResolution()boolThe resolution was out of range (code 4)
isPentagonError()boolPentagon distortion was encountered (code 9)
isNotNeighborsError()boolThe cells were not neighbors (code 11)

The numeric code also flows through to PHP's $e->getCode().

H3 error codes

The codes map to the H3 C library's standard error set:

CodeMeaning
0Success
1The operation failed but a more specific error is not available
2Argument was outside of acceptable range
3Latitude or longitude arguments were outside of acceptable range
4Resolution argument was outside of acceptable range
5H3Index cell argument was not valid
6H3Index directed edge argument was not valid
7H3Index undirected edge argument was not valid
8H3Index vertex argument was not valid
9Pentagon distortion was encountered
10Duplicate input was encountered in the arguments
11H3Index cell arguments were not neighbors
12H3Index cell arguments had incompatible resolutions
13Memory allocation failed
14Bounds of provided memory were not large enough
15Mode or flags argument was not valid

Common exceptions

Setup failures

These show up when you first construct an H3 instance and usually mean an installation step is incomplete — see Installation:

Message (abridged)Cause
The FFI extension is not loadedextension=ffi is missing from php.ini
FFI is not enabledffi.enable is not true / preload
Could not find H3 libraryNo bundled binary for your platform and no system H3

Input validation failures

H3 PHP validates every argument before it reaches C, so malformed input throws a clear H3Exception instead of triggering undefined behavior.

// Coordinates: NaN, Inf, or out of range are rejected
$h3->latLngToCell(NAN, 0.0, 9);     // throws — bad latitude
$h3->latLngToCell(91.0, 0.0, 9);    // throws — latitude out of range
 
// H3 strings: null bytes, invalid hex, or over-length are rejected
$h3->stringToH3('invalid!');        // throws — not valid hex
$h3->stringToH3("abc\0def");        // throws — embedded null byte
 
// Resolution relationships are enforced
$cell = $h3->latLngToCell(37.7749, -122.4194, 9);
$h3->cellToChildren($cell, 3);      // throws — child res must be finer than 9
$h3->cellToParent($cell, 10);       // throws — parent res must be coarser than 9

Always validate untrusted cell IDs

Cell indices arriving from API requests, uploads, or external databases are untrusted input. Run them through stringToH3 (which rejects null bytes and bad hex) and isValidCell before passing them to any other function. This is your sanitization boundary.

Memory safety

Grid operations like gridDisk grow quadratically with k. Left unbounded, a single large k could allocate gigabytes. H3 PHP caps k at a configurable limit to prevent that.

// Default max k is 500 — about 751,501 cells
$h3->gridDisk($cell, 1000);   // throws H3Exception (exceeds the limit)

setMaxGridK / getMaxGridK

Adjust the cap deliberately when your use case genuinely needs a larger disk:

public static function setMaxGridK(int $maxK): void
public static function getMaxGridK(): int
echo H3::getMaxGridK();        // 500 by default
 
H3::setMaxGridK(1000);         // raise the ceiling
$h3->gridDisk($cell, 1000);    // now allowed

Raise the limit with intent

The 500 default exists to protect your process. Before raising it, do the math: a disk at k is up to 3 * k * (k + 1) + 1 cells. At k = 1000 that's ~3 million cells. Set the limit only as high as your largest legitimate query, and prefer compaction over ever-larger disks for big areas.

Descriptive error messages

H3Exception messages combine your operation, the H3 description, and the code — so logs are self-explanatory:

try {
    $h3->cellToChildren($cell, 3);
} catch (H3Exception $e) {
    // "Failed to get children cells: H3Index cell arguments had
    //  incompatible resolutions (error code: 12)"
    echo $e->getMessage();
    echo $e->getH3ErrorCode();   // 12
}

Worked example — a safe ingestion guard

ingest.php
use Foysal50x\H3\H3;
use Foysal50x\H3\H3Exception;
 
$h3 = H3::getInstance();
 
function safeCell(H3 $h3, string $raw): ?int
{
    try {
        $cell = $h3->stringToH3($raw);
        return $h3->isValidCell($cell) ? $cell : null;
    } catch (H3Exception) {
        return null;   // null byte, bad hex, or over-length
    }
}
 
foreach (['8928308280fffff', "bad\0", 'zzz'] as $raw) {
    $cell = safeCell($h3, $raw);
    echo $raw === "bad\0" ? '[null-byte]' : $raw;
    echo ': ' . ($cell !== null ? 'accepted' : 'rejected') . PHP_EOL;
}

Next steps

H3 PHP — Hexagonal geospatial indexing for PHP. Released under the MIT license.