floci-io/floci · error · VtlErrorSignal
Unknown
Unknown
Error message
{message} What it means
This is the emulator's implementation of the AppSync VTL utility $util.error(message). In a request/response mapping template it aborts resolver execution and surfaces the given message to the GraphQL client as an error entry. It throws VtlErrorSignal with errorType 'Unknown', matching AppSync behavior when no type is provided.
Source
Thrown at src/main/java/io/github/hectorvent/floci/services/appsync/graphql/util/AppSyncUtil.java:205
return value instanceof Map<?, ?>;
}
public String typeOf(Object value) {
if (value == null) return "Null";
if (value instanceof String) return "String";
if (value instanceof Boolean) return "Boolean";
if (value instanceof Number) return "Number";
if (value instanceof List<?>) return "List";
if (value instanceof Map<?, ?>) return "Map";
return "Object";
}
public String authType() {
return authTypeValue;
}
public void error(String message) {
throw new VtlErrorSignal(message, "Unknown", null, null);
}
public void error(String message, String errorType) {
throw new VtlErrorSignal(message, errorType, null, null);
}
public void error(String message, String errorType, Object data) {
throw new VtlErrorSignal(message, errorType, data, null);
}
public void error(String message, String errorType, Object data, Object errorInfo) {
throw new VtlErrorSignal(message, errorType, data, errorInfo);
}
public void appendError(String message) {
appendErrorInternal(message, "Unknown", null, null);
}
View on GitHub (pinned to 62ff490619)
Solutions
- Inspect the GraphQL response's errors[0].message to identify which template branch called $util.error.
- If the abort is intentional, pass an error type: $util.error(message, "MyErrorType", $context.result) for structured handling.
- If it fires unexpectedly, log the template inputs ($ctx.args, $ctx.identity) before the $util.error call to see why the guard triggered.
- Handle the error client-side via the GraphQL errors array instead of HTTP status.
Example fix
## before
#if($ctx.args.input == "")
$util.error("input required")
#end
## after
#if($ctx.args.input == "")
$util.error("input required", "ValidationException")
#end Defensive patterns
Strategy: try-catch
Try / catch
// Server-side (emulator): VtlErrorSignal propagates out of VTL evaluation
try {
return evaluateTemplate(reqMapping, ctx);
} catch (VtlErrorSignal e) {
return graphqlErrorResponse(e.getMessage(), e.getErrorType());
}
// Client-side: inspect the GraphQL errors array
if (response.hasErrors()) {
log.warn("resolver error [{}]", response.getErrors().get(0).getMessage());
} Prevention
- Prefer $util.validate over bare $util.error for input checks so guards are explicit.
- Keep a single error-message catalog for your templates to find the failing branch fast.
- Always read the errors array, not just data, when testing resolvers.
When it happens
Trigger: A mapping template (resolver or function) calls $util.error("...") without an error type — for example a custom rejection branch in a DynamoDB put resolver or an if-guard that fails. The GraphQL response returns a non-null errors array and data is null for that field.
Common situations: Authors of VTL templates ported from AppSync that intentionally abort on bad input; debugging templates where an error branch fires unexpectedly (wrong $context arguments, missing identity).
Related errors
AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14).
Data as JSON: /api/errors/30fbf1fedb8ed99f.
Report an issue: GitHub.