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

  1. Inspect the GraphQL response's errors[0].message to identify which template branch called $util.error.
  2. If the abort is intentional, pass an error type: $util.error(message, "MyErrorType", $context.result) for structured handling.
  3. If it fires unexpectedly, log the template inputs ($ctx.args, $ctx.identity) before the $util.error call to see why the guard triggered.
  4. 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

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.