floci-io/floci · error · VtlErrorSignal

{errorType}

{errorType}

Error message

{message}

What it means

Implements $util.error(message, errorType) from AppSync VTL: aborts the resolver and reports the message with the caller-supplied errorType (e.g. 'Unauthorized', 'Conflict'). The emulator throws VtlErrorSignal carrying both fields; the GraphQL data-plane turns it into an error entry with errorType metadata.

Source

Thrown at src/main/java/io/github/hectorvent/floci/services/appsync/graphql/util/AppSyncUtil.java:209

        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);
    }

    public void appendError(String message, String errorType) {
        appendErrorInternal(message, errorType, null, null);
    }

View on GitHub (pinned to 62ff490619)

Solutions

  1. Check errors[0].errorType (or extensions) in the GraphQL response to find the originating template call.
  2. If the type is unexpected, fix the condition guarding the $util.error call rather than the message.
  3. Keep errorType strings aligned with AWS conventions (e.g. 'DynamoDB:ConditionalCheckFailedException') so SDK/AppSync tooling recognizes them.
  4. For recoverable cases, use $util.appendError instead so the resolver continues and returns data.

Example fix

## before
$util.error("write failed", "RandomError")

## after
$util.error("write failed", "DynamoDB:ConditionalCheckFailedException")
Defensive patterns

Strategy: try-catch

Try / catch

try {
    return evaluateTemplate(reqMapping, ctx);
} catch (VtlErrorSignal e) {
    if ("Unauthorized".equals(e.getErrorType())) throw new UnauthorizedException(e);
    throw new TypedGraphQLError(e.getMessage(), e.getErrorType(), e);
}

Prevention

When it happens

Trigger: A mapping template explicitly calls the two-argument form, e.g. $util.error("mutation failed", "DynamoDB:ConditionalCheckFailedException"). Common in mutation resolvers that translate downstream failures into typed GraphQL errors.

Common situations: Templates copied from AWS docs or blog posts that use typed $util.error for conditional-write failures; clients that switch on errorType and break when the type string doesn't match exactly.

Related errors


AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14). Data as JSON: /api/errors/14ef03b0bc9536c6. Report an issue: GitHub.