floci-io/floci · error · AwsException

InvalidArgument

InvalidArgument

Error message

Unknown tagging operation.

What it means

CloudFront exposes a single tagging endpoint (POST/GET ?Operation=...) that multiplexes TagResource and UntagResource based on the Operation query parameter. This controller only accepts Operation=Tag (with an XML Tags body) and Operation=Untag (with TagKeys); any other value — including a missing, misspelled, or wrong-case parameter — throws InvalidArgument 'Unknown tagging operation' (400).

Source

Thrown at src/main/java/io/github/hectorvent/floci/services/cloudfront/CloudFrontController.java:974

        } catch (AwsException e) {
            return xmlErrorResponse(e);
        }
    }

    @POST
    @Path("/tagging")
    public Response tagging(@QueryParam("Operation") String operation,
                            @QueryParam("Resource") String resource,
                            String body) {
        try {
            if ("Tag".equals(operation)) {
                Map<String, String> tags = parseTags(body);
                service.tagResource(resource, tags);
            } else if ("Untag".equals(operation)) {
                List<String> keys = XmlParser.extractAll(body, "Key");
                service.untagResource(resource, keys);
            } else {
                throw new AwsException("InvalidArgument", "Unknown tagging operation.", 400);
            }
            return Response.noContent().build();
        } catch (AwsException e) {
            return xmlErrorResponse(e);
        }
    }

    // ── Continuous Deployment Policies ───────────────────────────────────────

    @POST
    @Path("/continuous-deployment-policy")
    public Response createContinuousDeploymentPolicy(String body) {
        try {
            ContinuousDeploymentPolicy policy = parseContinuousDeploymentPolicy(body);
            policy = service.createContinuousDeploymentPolicy(policy);
            String xml = xmlContinuousDeploymentPolicyResponse(policy);
            return Response.created(URI.create("/2020-05-31/continuous-deployment-policy/" + policy.getId()))
                    .type(XML)

View on GitHub (pinned to 62ff490619)

Solutions

  1. Use exactly Operation=Tag for tagging and Operation=Untag for untagging, with the Resource query parameter set to the full ARN.
  2. Prefer the AWS SDK's tagResource/untagResource methods, which build the correct query string.
  3. Check for typos and casing in the query string — matching is case-sensitive ('Tag', not 'tag').
  4. Verify the request goes to POST /2020-05-31/tagging with the XML body (Tags or TagKeys) matching the operation.

Example fix

# before (throws InvalidArgument: Unknown tagging operation)
curl -X POST "$ENDPOINT/2020-05-31/tagging?Resource=$ARN" \
  -d '<Tags><Items><Tag><Key>env</Key><Value>prod</Value></Tag></Items></Tags>'

# after
curl -X POST "$ENDPOINT/2020-05-31/tagging?Operation=Tag&Resource=$ARN" \
  -d '<Tags><Items><Tag><Key>env</Key><Value>prod</Value></Tag></Items></Tags>'
Defensive patterns

Strategy: validation

Validate before calling

java.net.URI uri = java.net.URI.create(requestUrl);
String op = java.net.URLEncoder.encode("Tag", java.nio.charset.StandardCharsets.UTF_8);
// Assert the query string carries an accepted operation before sending
Map<String, String> q = java.net.URI.create(requestUrl).getRawQuery() == null
        ? Map.of() : java.util.Arrays.stream(java.net.URI.create(requestUrl).getRawQuery().split("&"))
            .map(p -> p.split("=", 2)).collect(java.util.stream.Collectors.toMap(p -> p[0], p -> p[1]));
if (!("Tag".equals(q.get("Operation")) || "Untag".equals(q.get("Operation"))) || q.get("Resource") == null) {
    throw new IllegalArgumentException("CloudFront tagging requires ?Operation=Tag|Untag and ?Resource=<arn>");
}

Try / catch

try {
    client.tagResource(r -> r.resource(arn).tags(t -> t.items(tagList)));
} catch (CloudFrontException e) {
    if ("InvalidArgument".equals(e.awsErrorDetails().errorCode())
            && e.getMessage().contains("tagging")) {
        // custom HTTP layer dropped/mangled the Operation query param; rebuild request
        throw new IllegalStateException("Tagging request missing Operation=Tag|Untag", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: POST to /2020-05-31/tagging?Resource=<arn> without an Operation query parameter; Operation=tag (lowercase) or Operation=TagResource; a typo like Operation=UntagResource; calling with Operation=ListTags, which this endpoint does not support.

Common situations: SDK TagResource/UntagResource calls routed to a wrong path by a custom HTTP layer; handcrafted curl requests that forget the query param; code ported from other AWS tagging APIs that use separate endpoints per verb; case-sensitive comparisons surprising users.

Related errors


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