Skip to content

GeoLeaf.Errors — Errors module documentation

Applies to: @geoleaf/core v3.x

Source: src/modules/utils/errors/index.ts


Overview

The GeoLeaf.Errors module provides typed error classes for consistent, contextual error handling across the whole GeoLeaf library.

Benefits of typed errors

  • Targeted catch — tell error types apart with instanceof
  • Richer context — additional debugging data (error.context)
  • Clean stack trace — call stack preserved through captureStackTrace
  • Serialisable — JSON conversion through toJSON()
  • Timestamp — automatic time stamping (error.timestamp)
  • Error code — machine-readable identifier (error.code)

Error hierarchy

Error (native)
  └─ GeoLeafError (base)
      ├─ ValidationError     VALIDATION_ERROR
      ├─ SecurityError       SECURITY_ERROR
      ├─ ConfigError         CONFIG_ERROR
      ├─ NetworkError        NETWORK_ERROR
      ├─ InitializationError INITIALIZATION_ERROR
      ├─ MapError            MAP_ERROR
      ├─ DataError           DATA_ERROR
      ├─ POIError            POI_ERROR
      ├─ RouteError          ROUTE_ERROR
      └─ UIError             UI_ERROR

Error classes

GeoLeafError (base)

Base class for every GeoLeaf error. It extends the native Error.

Properties:

PropertyTypeDescription
namestringClass name (for example 'ValidationError')
messagestringError message
contextErrorContextAdditional context data
timestampstringISO 8601 creation time
codestringMachine code (defined in each subclass)
stackstringStack trace

Methods:

  • toJSON() — returns a serialisable object { name, message, context, timestamp, stack }
  • toString() — readable formatting with context: "ErrorName: message [Context: {...}]"
js
const error = new GeoLeaf.Errors.GeoLeafError("Generic error", {
    module: "Core",
    operation: "init",
});

console.log(error.name); // 'GeoLeafError'
console.log(error.message); // 'Generic error'
console.log(error.context); // { module: 'Core', operation: 'init' }
console.log(error.timestamp); // '2026-03-15T10:30:00.000Z'
console.log(error.code); // undefined (base class)

ValidationError

Data validation error. Code: VALIDATION_ERROR

Used for:

  • Invalid coordinates
  • Missing or incorrect parameters
  • Non-conforming data format
js
throw new GeoLeaf.Errors.ValidationError("Latitude must be between -90 and 90", {
    lat: 95,
    lng: -73,
    expected: "Range: -90 to 90",
});

// Targeted catch
try {
    GeoLeaf.Core.init({/* options */});
} catch (error) {
    if (error instanceof GeoLeaf.Errors.ValidationError) {
        console.error("Validation error:", error.context);
    }
}

SecurityError

Security issue detected. Code: SECURITY_ERROR

Used for:

  • XSS content detection
  • Disallowed URL protocol
  • Non-image data URL
js
throw new GeoLeaf.Errors.SecurityError("Protocol not allowed: javascript:", {
    url: "javascript:alert(1)",
    allowedProtocols: ["http:", "https:", "data:"],
});

try {
    GeoLeaf.Validators.validateUrl(userUrl, { throwOnError: true });
} catch (error) {
    if (error instanceof GeoLeaf.Errors.SecurityError) {
        console.error("Security attempt detected");
        // Log it for analysis
    }
}

ConfigError

Configuration error. Code: CONFIG_ERROR

Used for:

  • Invalid JSON configuration
  • Missing configuration field
  • Incorrect profile structure
js
throw new GeoLeaf.Errors.ConfigError("Invalid profile structure: missing layers", {
    profileId: "tourism",
    expected: "Array",
    received: "undefined",
});

try {
    GeoLeaf.Config.loadProfile("tourism");
} catch (error) {
    if (error instanceof GeoLeaf.Errors.ConfigError) {
        console.error("Incorrect configuration:", error.message);
    }
}

NetworkError

Network or HTTP error. Code: NETWORK_ERROR

Used for:

  • fetch() failure
  • Network timeout
  • HTTP 4xx/5xx status
js
throw new GeoLeaf.Errors.NetworkError("Failed to load POI data", {
    url: "/api/poi",
    status: 404,
    statusText: "Not Found",
});

async function loadWithRetry() {
    try {
        return await GeoLeaf.Config.loadConfig("config.json");
    } catch (error) {
        if (error instanceof GeoLeaf.Errors.NetworkError) {
            console.warn("Retrying in 3s...");
            await GeoLeaf.Helpers.wait(3000);
            return await GeoLeaf.Config.loadConfig("config.json");
        }
        throw error;
    }
}

InitializationError

Error raised during initialisation. Code: INITIALIZATION_ERROR

Used for:

  • Map creation failure
  • DOM element not found
  • Missing dependency
js
throw new GeoLeaf.Errors.InitializationError("Failed to create map: target element not found", {
    target: "map-container",
    domReady: document.readyState,
});

MapError

Error related to the MapLibre map. Code: MAP_ERROR

Used for:

  • Invalid map operation
  • Invalid bounds
  • Layer not found
js
throw new GeoLeaf.Errors.MapError("Cannot fit bounds: no features loaded", {
    operation: "fitBounds",
    featureCount: 0,
});

DataError

Generic data error. Code: DATA_ERROR

Used for:

  • Malformed data not specific to POI/Route/GeoJSON
  • Failed data parsing
js
throw new GeoLeaf.Errors.DataError("Invalid data structure", {
    source: "api/response",
    expected: "array",
    received: typeof data,
});

POIError

Error raised while handling POIs. Code: POI_ERROR

Used for:

  • Malformed POI
  • Failed POI loading
  • Invalid marker
js
throw new GeoLeaf.Errors.POIError("Invalid POI: missing latlng", {
    poiId: "poi-123",
    provided: { id: "poi-123", label: "Test" },
    expected: "latlng: [lat, lng]",
});

RouteError

Error raised while processing routes. Code: ROUTE_ERROR

Used for:

  • Malformed GPX
  • Failed GPX parsing
  • Empty route
js
throw new GeoLeaf.Errors.RouteError("Failed to parse GPX: invalid XML", {
    url: "route.gpx",
    parseError: "Unexpected end of input",
});

UIError

Error related to the user interface. Code: UI_ERROR

Used for:

  • UI component not initialised
  • Failed rendering
  • DOM element missing during a UI operation
js
throw new GeoLeaf.Errors.UIError("Panel render failed: container not found", {
    panelId: "sidepanel",
    operation: "render",
});

Constants

ErrorCodes

Immutable object listing every error code:

js
GeoLeaf.Errors.ErrorCodes.VALIDATION; // 'VALIDATION_ERROR'
GeoLeaf.Errors.ErrorCodes.SECURITY; // 'SECURITY_ERROR'
GeoLeaf.Errors.ErrorCodes.CONFIG; // 'CONFIG_ERROR'
GeoLeaf.Errors.ErrorCodes.NETWORK; // 'NETWORK_ERROR'
GeoLeaf.Errors.ErrorCodes.INITIALIZATION; // 'INITIALIZATION_ERROR'
GeoLeaf.Errors.ErrorCodes.MAP; // 'MAP_ERROR'
GeoLeaf.Errors.ErrorCodes.DATA; // 'DATA_ERROR'
GeoLeaf.Errors.ErrorCodes.POI; // 'POI_ERROR'
GeoLeaf.Errors.ErrorCodes.ROUTE; // 'ROUTE_ERROR'
GeoLeaf.Errors.ErrorCodes.UI; // 'UI_ERROR'

Utility functions

normalizeError(error, defaultMessage?)

Normalises any value into a GeoLeafError.

js
try {
    // risky code
} catch (rawError) {
    const err = GeoLeaf.Errors.normalizeError(rawError, "Unexpected error");
    GeoLeaf.Log.error(err.toString());
}

isErrorType(error, ErrorClass)

Checks whether an error is an instance of a given class.

js
const isConfig = GeoLeaf.Errors.isErrorType(error, GeoLeaf.Errors.ConfigError);

getErrorCode(error)

Extracts the error code from any value.

js
const code = GeoLeaf.Errors.getErrorCode(error);
// 'VALIDATION_ERROR' | 'CONFIG_ERROR' | ... | 'UNKNOWN_ERROR'

createError(ErrorClass, message, context?)

Creates a typed error instance with a clean stack trace.

js
const err = GeoLeaf.Errors.createError(GeoLeaf.Errors.ValidationError, "Invalid zoom level", {
    zoom: 25,
    max: 20,
});

createErrorByType(type, message, context?)

Creates an error from its type given as a string.

js
const err = GeoLeaf.Errors.createErrorByType("validation", "Invalid value", { value: 42 });
// Returns a ValidationError instance

Supported types: 'validation', 'security', 'config', 'network', 'initialization', 'map', 'data', 'poi', 'route', 'ui'


sanitizeErrorMessage(message, maxLength?)

Sanitises an error message (HTML escaping, truncation).

js
const safe = GeoLeaf.Errors.sanitizeErrorMessage(userInput, 500);

safeErrorHandler(handler, error)

Runs an error handler safely (guards against errors thrown inside handlers).

js
GeoLeaf.Errors.safeErrorHandler(onError, caughtError);

Usage patterns

Pattern 1: validation with a typed error

js
function validatePOI(poi) {
    if (!poi.latlng || !Array.isArray(poi.latlng)) {
        throw new GeoLeaf.Errors.ValidationError("POI must have latlng array", {
            poiId: poi.id,
            provided: poi.latlng,
        });
    }
    GeoLeaf.Validators.validateCoordinates(poi.latlng[0], poi.latlng[1], {
        throwOnError: true,
    });
    // ValidationError is thrown automatically when invalid
}

Pattern 2: multi-level catch

js
try {
    await GeoLeaf.Config.loadConfig("config.json");
} catch (error) {
    if (error instanceof GeoLeaf.Errors.NetworkError) {
        console.error("Network problem, offline mode enabled");
        activateOfflineMode();
    } else if (error instanceof GeoLeaf.Errors.ConfigError) {
        console.error("Invalid configuration");
        showConfigHelp();
    } else if (error instanceof GeoLeaf.Errors.SecurityError) {
        console.error("Security problem detected");
        reportSecurityIssue(error);
    } else {
        console.error("Unknown error:", error);
    }
}

Pattern 3: enriched logging

js
try {
    // Risky code
} catch (error) {
    if (error instanceof GeoLeaf.Errors.GeoLeafError) {
        GeoLeaf.Log.error("[GeoLeaf] Error:", {
            type: error.name,
            code: error.code,
            message: error.message,
            context: error.context,
            timestamp: error.timestamp,
        });
    } else {
        GeoLeaf.Log.error("[GeoLeaf] Unknown error:", error);
    }
}

Pattern 4: using normalizeError in generic handlers

js
async function safeLoad(url) {
    try {
        const res = await fetch(url);
        if (!res.ok) {
            throw new GeoLeaf.Errors.NetworkError(`HTTP ${res.status}`, {
                url,
                status: res.status,
            });
        }
        return await res.json();
    } catch (rawError) {
        const err = GeoLeaf.Errors.normalizeError(rawError, "Load failed");
        GeoLeaf.Log.error("[GeoLeaf] Load error:", err.toString());
        throw err;
    }
}

Tests

bash
npm test -- errors

# Test files
# packages/core/__tests__/core/errors.test.js
# packages/core/__tests__/core/errors-extended.test.js

Coverage: 95%+ (150+ passing tests)


Error statistics

Error typeFrequencyCriticality
ValidationError45%Medium
ConfigError25%High
NetworkError15%Medium
SecurityError5%High
Others10%Variable

Changelog

v2.0.0 — first official release

  • Module created with the base hierarchy: GeoLeafError, ValidationError, SecurityError, ConfigError, NetworkError, InitializationError, MapError
  • Added DataError and UIError
  • Added ErrorCodes (machine-readable constants)
  • Added utility functions: normalizeError, isErrorType, getErrorCode, createError, createErrorByType, sanitizeErrorMessage, safeErrorHandler

See also

  • GeoLeaf.Validators — uses ValidationError and SecurityError
  • GeoLeaf.Security — uses SecurityError
  • GeoLeaf.Config — uses ConfigError and NetworkError
  • GeoLeaf.Log — error logging

Released under the MIT License.