floci-io/floci · error · VtlErrorSignal
Unauthorized
Unauthorized
Error message
Not Authorized
What it means
Implements $util.unauthorized(): the VTL equivalent of rejecting a request for missing/failed authorization. The resolver aborts with message 'Not Authorized' and errorType 'Unauthorized', mirroring AppSync's behavior when authorization checks in a mapping template fail.
Source
Thrown at src/main/java/io/github/hectorvent/floci/services/appsync/graphql/util/AppSyncUtil.java:248
}
public void appendError(String message, String errorType, Object data, Object errorInfo) {
appendErrorInternal(message, errorType, data, errorInfo);
}
private void appendErrorInternal(String message, String errorType, Object data, Object errorInfo) {
if (errorList != null) {
Map<String, Object> error = new LinkedHashMap<>();
error.put("message", message);
error.put("type", errorType);
if (data != null) error.put("data", data);
if (errorInfo != null) error.put("errorInfo", errorInfo);
errorList.add(error);
}
}
public void unauthorized() {
throw new VtlErrorSignal("Not Authorized", "Unauthorized", null, null);
}
public void validate(boolean condition, String message) {
validate(condition, message, "CustomTemplateException");
}
public void validate(boolean condition, String message, String errorType) {
validate(condition, message, errorType, null);
}
public void validate(boolean condition, String message, String errorType, Object data) {
if (!condition) {
throw new VtlErrorSignal(message, errorType, data, null);
}
}
}
View on GitHub (pinned to 62ff490619)
Solutions
- Send the correct authorization for the API's auth mode: signed requests (SigV4 for IAM), Authorization header (Cognito JWT), or x-api-key header.
- Verify the identity claim the template checks actually exists, e.g. decode the JWT and inspect $ctx.identity.claims.
- Relax or fix the template guard if it rejects legitimate users (wrong group name, null-check inverted).
- In the emulator, ensure the AppSync API's default authentication mode matches what the client uses.
Example fix
## before
#if(!$ctx.identity.claims.get("cognito:groups").contains("admins"))
$util.unauthorized()
#end
## after
#set($groups = $util.defaultIfNull($ctx.identity.claims.get("cognito:groups"), []))
#if(!$groups.contains("admins"))
$util.unauthorized()
#end Defensive patterns
Strategy: validation
Validate before calling
// Client: prove credentials are present before the GraphQL call
if (authMode == IAM && signingCredentials == null) throw new IllegalStateException("IAM credentials required");
if (authMode == API_KEY && apiKey == null) throw new IllegalStateException("API key required");
if (authMode == USER_POOLS && jwt == null) throw new IllegalStateException("Cognito token required"); Try / catch
if (response.hasErrors() && response.getErrors().stream()
.anyMatch(er -> "Unauthorized".equals(er.getErrorType()) || "Not Authorized".equals(er.getMessage()))) {
throw new UnauthorizedException("refresh credentials and retry");
} Prevention
- Refresh tokens/signing credentials before they expire; treat Unauthorized as non-retryable until re-auth.
- Match the client auth mechanism to the API's default authorization mode.
- Null-guard $ctx.identity and its claims inside templates before dereferencing.
When it happens
Trigger: A request/response mapping template calls $util.unauthorized() — e.g. #if($ctx.identity == null) or a group-membership check like #if(!$ctx.identity.claims.get("cognito:groups").contains("admins")) — and the guard trips. Common in field-level authorization on top of API-level auth.
Common situations: Cognito/API-key authorizers where the test client sends no or wrong credentials; AppSync API configured with IAM auth but the request signed with a different mechanism; role/group claim names that don't match what the template checks after migrating identity providers.
Related errors
AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14).
Data as JSON: /api/errors/dc7b398fe4eb3a71.
Report an issue: GitHub.