Skip to content

Errors & exceptions

The error taxonomy is how your component tells which subsystem failed — config, schema validation, messaging, credentials, parameters, or streaming — and decides whether to recover or abort. Each SDK exposes the same set of failure modes, but in its own idiomatic shape, so the type you catch differs by language even when the underlying cause is identical.

There is no single, unified error type across the four languages. Only Rust unifies everything into one enum; TypeScript unifies the core subsystems only; Java and Python use a distinct exception class per subsystem.

A small set of subsystem exceptions in com.mbreissi.ggcommons. Some are checked (the compiler forces a try/catch or throws), some are unchecked (RuntimeException).

// package com.mbreissi.ggcommons.*
class ConfigurationException extends Exception // CHECKED — config.ConfigurationException
class ConfigurationValidator.ConfigurationValidationException // CHECKED — nested static in config.ConfigurationValidator
extends Exception
class CredentialException extends RuntimeException // unchecked — credentials.CredentialException
class ParameterException extends RuntimeException // unchecked — parameters.ParameterException
class GgStreamException extends RuntimeException { // unchecked — streaming.GgStreamException
GgStreamException(int code, String message);
int code(); // the underlying ggsl_status value
// constants mirroring ggsl_status:
// OK=0, ERR_CONFIG=1, ERR_IO=2, ERR_CORRUPT=3, ERR_FULL=4,
// ERR_UNKNOWN_STREAM=5, ERR_SINK=6, ERR_PANIC=7, ERR_INVALID_ARG=8
}

CLI and builder preconditions throw the standard IllegalArgumentException (e.g. unknown --platform / --transport, the removed -m/--mode flag) and IllegalStateException (builder precondition violations).

The same logical failure maps to a different type in each SDK. Read across a row to translate.

Subsystem failure Java Python Rust TypeScript
CLI / arg validation IllegalArgumentException ValueError GgError::Cli GgError kind "Cli"
Config load ConfigurationException (checked) ValueError / propagated GgError::Config GgError kind "Config"
Schema validation ConfigurationValidationException (checked) ConfigurationValidationException GgError::Validation GgError kind "Validation"
Messaging standard exception (no dedicated class) standard exception (no dedicated class) GgError::Messaging GgError kind "Messaging"
Metrics standard exception (no dedicated class) standard exception (no dedicated class) GgError::Metrics GgError kind "Metrics"
Greengrass IPC standard exception (no dedicated class) standard exception (no dedicated class) GgError::Ipc GgError kind "Ipc"
Credentials CredentialException CredentialError GgError::Credentials CredentialError
Parameters ParameterException ParameterError GgError::Parameters ParameterError
Streaming GgStreamException (+code()) GgStreamError (+.code) GgError::Streaming (code discarded) GgStreamError (+.code)
I/O · JSON JDK IOException etc. stdlib exceptions GgError::Io / GgError::Json GgError kind "Io" / "Json"
  • ConfigurationException — thrown by ConfigManagerFactory.create(...) when no configuration is found, or when a ConfigManager cannot be created. It is not thrown by ConfigManager itself.
  • ConfigurationValidationException — thrown by ConfigurationValidator.validate(JsonObject) when the config violates the canonical JSON schema. It is fail-closed: a missing schema resource on the classpath also throws (it does not silently pass).
  • CredentialException — vault open/decrypt failures: a wrong KEK, tampered data, an unsupported vault format, or corrupt JSON. Messages never include secret or key material.
  • ParameterException — parameter resolution/decryption failures (the parameters subsystem reuses the credentials vault as an encrypted cache).
  • GgStreamException — any non-zero ggsl_status from the native ggstreamlog engine; inspect code() (e.g. ERR_UNKNOWN_STREAM, ERR_CONFIG, ERR_FULL) to branch.

Streaming is the one place that carries a numeric status (ggsl_status from the native ggstreamlog engine) — but only three of the four SDKs preserve it.

GgStreamException.code() returns the int, and named constants are exposed (GgStreamException.ERR_FULL, ERR_UNKNOWN_STREAM, …) so you can branch on a name.

GgStreamException ex = assertThrows(GgStreamException.class, () -> svc.stats("nope"));
assertEquals(GgStreamException.ERR_UNKNOWN_STREAM, ex.code()); // 5

Optional subsystems return empty, they do not throw

Section titled “Optional subsystems return empty, they do not throw”

Credentials, parameters, and streaming are opt-in: when the matching config section is absent (and, in Rust, the matching cargo feature is enabled), the accessor returns an empty value rather than throwing. Always check before use.

getStreams(), getCredentials(), and getParameters() return null when the section is absent. getMessaging() and getMetrics() return the wired subsystem.

var creds = gg.getCredentials();
if (creds == null) {
// no `credentials` config section — feature is off
} else {
var secret = creds.get("db-password");
}

A minimal, idiomatic handler in each language — catch the validation error to abort startup, and branch on the streaming status code where it is available.

import com.mbreissi.ggcommons.config.ConfigurationValidator;
import com.mbreissi.ggcommons.config.ConfigurationValidator.ConfigurationValidationException;
import com.mbreissi.ggcommons.streaming.GgStreamException;
// Checked: the compiler forces you to handle (or declare) this one.
try {
ConfigurationValidator.validate(config); // JsonObject
} catch (ConfigurationValidationException e) {
log.error("config rejected: {}", e.getMessage()); // lists each schema violation
throw new IllegalStateException("cannot start", e); // abort startup
}
// Unchecked, code-bearing.
try {
var stats = gg.getStreams().stats("telemetry");
} catch (GgStreamException e) {
if (e.code() == GgStreamException.ERR_FULL) {
// durable buffer is full — back off and retry later
} else {
throw e;
}
}

Whether a failure (or shutdown) ends the OS process differs sharply across the SDKs. This matters when a supervisor (the Nucleus, a container runtime, Kubernetes) watches the exit code.