Skip to content

Fix #2941: make aws-ddb-sink honour its own operation property - #2992

Merged
oscerd merged 1 commit into
apache:mainfrom
oscerd:ci-issue-2941
Sep 1, 2026
Merged

Fix #2941: make aws-ddb-sink honour its own operation property#2992
oscerd merged 1 commit into
apache:mainfrom
oscerd:ci-issue-2941

Conversation

@oscerd

@oscerd oscerd commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Fixes #2941.

The issue suspected this might need a runtime fix in apache/camel. It does not — the cause is in the Kamelet, and it is a two-character-shaped fix.

Root cause

aws-ddb-sink declared an inbound data type default:

  dataTypes:
    in:
      default: json
      types:
        json:
          format: "aws2-ddb:application-json"

Declaring a default input type makes Camel apply that transformation at the kamelet:source boundary — before any step in the template runs. Verified by logging the headers as the very first step of the template:

STEP-1 headers=[{CamelAwsDdbOperation=PutItem, CamelAwsDdbItem={...}, CamelAwsDdbReturnValues=ALL_OLD}]

The message is already transformed on arrival. Two consequences:

  1. setProperty operation ran after the transformer had already resolved the operation from the body alone and defaulted to PutItem. A log placed between the two showed ${exchangeProperty.operation} = UpdateItem while the transform had already happened — which is why this looked so puzzling.
  2. The transformer stamps CamelAwsDdbOperation, and in Ddb2Producer that header beats the endpoint's operation={{operation}} parameter. So the Kamelet's operation property could never take effect.

The in-template transformDataType step was dead code as a result — Ddb2JsonDataTypeTransformer returns early once CamelAwsDdbItem or CamelAwsDdbKey is present.

This also explains the reported workaround exactly: setting the exchange property in the calling route works because it is on the exchange before the boundary transformation.

Fix

Drop only the default: key. The transformation then happens at the existing transformDataType step, after the operation is set.

   dataTypes:
     in:
-      default: json
       types:

All the declared input-type documentation — schema, CamelAwsDdbOperation / CamelAwsDdbReturnValues header docs, description — is preserved. I deliberately did not remove the whole dataTypes block (which also works) because that metadata is worth keeping.

Verification

Probed each operation with camel run, swapping the terminal aws2-ddb endpoint for a log so the resolved headers are visible:

operation headers produced correct?
PutItem CamelAwsDdbItem + ALL_OLD
DeleteItem CamelAwsDdbKey + ALL_OLD
UpdateItem CamelAwsDdbKey + CamelAwsDdbUpdateValues + ALL_NEW

Before the change UpdateItem produced the PutItem shape — CamelAwsDdbItem + ALL_OLD — which is the reported bug.

The itest workaround is removed. aws-ddb-sink-route.yaml set the operation exchange property in the calling route; that is deleted here, so the test now exercises the Kamelet's own operation property rather than the workaround. AwsIT passes end to end against DynamoDB:

Tests run: 15, Failures: 0, Errors: 0, Skipped: 0 -- in AwsIT
   PASS  awsDdb()[1]   PASS  awsDdb()[2]   PASS  awsDdb()[3]   PASS  awsDdb()[4]

Run with CITRUS_CAMEL_CLI_KAMELETS_LOCAL_DIR pointed at this working tree, since without #2987 the itests resolve the released catalog and would not have exercised this change at all.

script/validator reports no errors and mvn clean install passes from the repository root.

Note for reviewers

Two other Kamelets declare dataTypes and carry an in-template transformDataTypeaws-ddb-streams-source and google-sheets-sink. That combination is what produced this bug here. I have not touched them: a source's out data type is a different code path and neither has a reported defect, so they are worth a look separately rather than a speculative change in this PR.


Claude Code on behalf of Andrea Cosentino

The Kamelet declared an inbound data type default:

    dataTypes:
      in:
        default: json

which makes Camel apply the aws2-ddb:application-json transformation at
the kamelet:source boundary, before any template step runs. So by the time
"setProperty operation" executed, the transformer had already resolved the
operation from the body alone, defaulted to PutItem and stamped
CamelAwsDdbOperation. That header then beat the endpoint's
operation={{operation}} parameter in Ddb2Producer, leaving the Kamelet's
operation property with no effect.

The in-template transformDataType step was a no-op as a result: the
transformer returns early once CamelAwsDdbItem or CamelAwsDdbKey is set.

Dropping only the "default:" key stops the transformation happening at the
boundary and lets the existing transformDataType step apply it after the
operation is set. All of the declared input-type documentation -- schema,
header docs, description -- is preserved.

Probed each operation with `camel run`, replacing the terminal aws2-ddb
endpoint with a log so the resolved headers are visible:

  PutItem     CamelAwsDdbItem + ALL_OLD
  DeleteItem  CamelAwsDdbKey + ALL_OLD
  UpdateItem  CamelAwsDdbKey + CamelAwsDdbUpdateValues + ALL_NEW

Before the change UpdateItem produced the PutItem shape.

The itest route carried a workaround that set the operation exchange
property in the calling route; it is removed here, so the test now
exercises the Kamelet's own property. AwsIT passes end to end against
DynamoDB: 15 tests, 0 failures, all four ddb cases green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@oscerd
oscerd merged commit c7b47c2 into apache:main Sep 1, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AWS DDB sink Kamelet does not reliably set the DynamoDB operation

1 participant