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:
| Method | Returns | Meaning |
|---|---|---|
getMessage() | string | Full message, including the description and code |
getH3ErrorCode() | int | The numeric H3 error code |
getH3ErrorDescription() | string | Human-readable description of the code |
isInvalidCell() | bool | The cell argument was not valid (code 5) |
isInvalidResolution() | bool | The resolution was out of range (code 4) |
isPentagonError() | bool | Pentagon distortion was encountered (code 9) |
isNotNeighborsError() | bool | The 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:
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | The operation failed but a more specific error is not available |
| 2 | Argument was outside of acceptable range |
| 3 | Latitude or longitude arguments were outside of acceptable range |
| 4 | Resolution argument was outside of acceptable range |
| 5 | H3Index cell argument was not valid |
| 6 | H3Index directed edge argument was not valid |
| 7 | H3Index undirected edge argument was not valid |
| 8 | H3Index vertex argument was not valid |
| 9 | Pentagon distortion was encountered |
| 10 | Duplicate input was encountered in the arguments |
| 11 | H3Index cell arguments were not neighbors |
| 12 | H3Index cell arguments had incompatible resolutions |
| 13 | Memory allocation failed |
| 14 | Bounds of provided memory were not large enough |
| 15 | Mode 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 loaded | extension=ffi is missing from php.ini |
FFI is not enabled | ffi.enable is not true / preload |
Could not find H3 library | No 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 9Always 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(): intecho H3::getMaxGridK(); // 500 by default
H3::setMaxGridK(1000); // raise the ceiling
$h3->gridDisk($cell, 1000); // now allowedRaise 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
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;
}