This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 7f3ea874a499 CAMEL-25550: camel-jpa, camel-hazelcast - a transacted 
consumer must not commit an exchange marked rollback only (#27681)
7f3ea874a499 is described below

commit 7f3ea874a4994eac62dd1a537efeba9c0646650b
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Oct 12 17:08:07 2026 +0200

    CAMEL-25550: camel-jpa, camel-hazelcast - a transacted consumer must not 
commit an exchange marked rollback only (#27681)
    
    * CAMEL-25550: camel-jpa, camel-hazelcast - a transacted consumer must not 
commit an exchange marked rollback only
    
    An exchange marked rollback only (markRollbackOnly(), 
markRollbackOnlyLast()) has no exception, so the JPA consumer deleted the 
entity (or called @Consumed) and committed the poll, and the transacted 
Hazelcast SEDA consumer committed its transaction, removing the message from 
the queue. The JPA consumer now does not consume such an entity: with 
transacted=true it throws a RollbackExchangeException so the whole poll is 
rolled back, with transacted=false it skips the entity and continue [...]
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
    
    * CAMEL-25550: Address review feedback
    
    Fix the grammar of the rollback only exception message, and move the
    upgrade guide note from 4.23 to 4.24 as this does not go into 4.23.0.
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
    
    * CAMEL-25550: the docs say an entity is consumed again only while it 
matches the query, and what a message always rolled back does now
    
    With transacted=false a change made by @PreConsumed is committed with the 
poll, so an entity it moved out of the
    query is not polled again. The upgrade note also says that a message always 
marked rollback only, which was removed
    before, is now consumed again at every poll (JPA) or taken again at once 
(transacted Hazelcast SEDA, see CAMEL-25589).
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
    Claude-Session: https://claude.ai/code/session_01STT6whBgK1AqsSsUKrnE8m
    
    ---------
    
    Signed-off-by: Claus Ibsen <[email protected]>
    Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
---
 .../apache/camel/catalog/docs/jpa-component.adoc   |   7 +
 .../hazelcast/seda/HazelcastSedaConsumer.java      |  13 +-
 .../HazelcastSedaTransactedRollbackOnlyTest.java   | 112 +++++++++++++++
 .../camel-jpa/src/main/docs/jpa-component.adoc     |   7 +
 .../apache/camel/component/jpa/JpaConsumer.java    |  17 +++
 .../component/jpa/JpaConsumerRollbackOnlyTest.java | 155 +++++++++++++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    |  16 +++
 7 files changed, 322 insertions(+), 5 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jpa-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jpa-component.adoc
index a61fe52350fc..72d7b1e71ffb 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jpa-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jpa-component.adoc
@@ -92,6 +92,13 @@ processed (such as to exclude it from a future query), then 
you can
 annotate a method with `@Consumed` (org.apache.camel.component.jpa.Consumed).
 It will be invoked on your entity bean when the entity bean has been processed 
(and when routing is done).
 
+An entity bean is only deleted (or `@Consumed` invoked) when its exchange 
completed successfully. If the route marks
+the exchange rollback only (for example with `markRollbackOnly()`), the entity 
bean is not consumed and stays in the
+table, so the next poll consumes it again, as long as it still matches the 
query. With `transacted=false` the other
+entity beans of the poll are still consumed, and so is what a `@PreConsumed` 
method changed before routing: an entity
+bean that `@PreConsumed` moved out of the query is not polled again. With 
`transacted=true` the whole poll is rolled
+back, the changes of `@PreConsumed` included.
+
 You can use `@PreConsumed` (org.apache.camel.component.jpa.PreConsumed)
 which will be invoked on your entity bean before it has been processed
 (before routing).
diff --git 
a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaConsumer.java
 
b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaConsumer.java
index bae894aebd1e..a444a6c19d42 100644
--- 
a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaConsumer.java
+++ 
b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaConsumer.java
@@ -115,16 +115,19 @@ public class HazelcastSedaConsumer extends 
DefaultConsumer implements Runnable {
                         // process using the asynchronous routing engine
                         processor.process(exchange, new AsyncCallback() {
                             public void done(boolean asyncDone) {
+                                // a rollback only exchange (without an 
exception) did not complete successfully either
+                                boolean rollback = exchange.getException() != 
null || exchange.isRollbackOnly()
+                                        || exchange.isRollbackOnlyLast();
+                                if (rollback && txc != null) {
+                                    LOG.trace("Rollback transaction: {}", 
txc.getTxnId());
+                                    txc.rollbackTransaction();
+                                }
                                 if (exchange.getException() != null) {
-                                    // Rollback
-                                    if (txc != null) {
-                                        txc.rollbackTransaction();
-                                    }
                                     
getExceptionHandler().handleException("Error processing exchange", exchange,
                                             exchange.getException());
                                 }
                                 // It's OK, I commit
-                                if (exchange.getException() == null && txc != 
null) {
+                                if (!rollback && txc != null) {
                                     LOG.trace("Commit transaction: {}", 
txc.getTxnId());
                                     txc.commitTransaction();
                                 }
diff --git 
a/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/HazelcastSedaTransactedRollbackOnlyTest.java
 
b/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/HazelcastSedaTransactedRollbackOnlyTest.java
new file mode 100644
index 000000000000..c92b55743aba
--- /dev/null
+++ 
b/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/HazelcastSedaTransactedRollbackOnlyTest.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.hazelcast;
+
+import java.util.concurrent.TimeUnit;
+
+import com.hazelcast.collection.IQueue;
+import com.hazelcast.core.HazelcastInstance;
+import com.hazelcast.transaction.TransactionContext;
+import com.hazelcast.transaction.TransactionalQueue;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+
+import static org.mockito.AdditionalAnswers.answersWithDelay;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * A message whose exchange was marked rollback only (without an exception) 
must roll back the Hazelcast transaction, so
+ * the message is not removed from the queue.
+ */
+public class HazelcastSedaTransactedRollbackOnlyTest extends 
HazelcastCamelTestSupport {
+
+    @Mock
+    private IQueue<Object> queue;
+
+    @Mock
+    private TransactionalQueue<Object> tqueue;
+
+    private final TransactionContext okTransaction = 
Mockito.mock(TransactionContext.class);
+    private final TransactionContext kaboomTransaction = 
Mockito.mock(TransactionContext.class);
+    private final TransactionContext idleTransaction = 
Mockito.mock(TransactionContext.class);
+
+    @Override
+    protected void trainHazelcastInstance(HazelcastInstance hazelcastInstance) 
{
+        // one transaction per polled message, and then one for each (empty) 
poll after
+        when(hazelcastInstance.newTransactionContext())
+                .thenReturn(okTransaction, kaboomTransaction, idleTransaction);
+        when(hazelcastInstance.getQueue("foo")).thenReturn(queue);
+        for (TransactionContext transaction : new TransactionContext[] { 
okTransaction, kaboomTransaction, idleTransaction }) {
+            when(transaction.getQueue("foo")).thenReturn(tqueue);
+        }
+    }
+
+    @Override
+    protected void verifyHazelcastInstance(HazelcastInstance 
hazelcastInstance) {
+        verify(hazelcastInstance, atLeastOnce()).getQueue("foo");
+        verify(hazelcastInstance, atLeastOnce()).newTransactionContext();
+    }
+
+    @Test
+    public void testRollbackOnlyRollsBackTransaction() throws Exception {
+        when(tqueue.poll(anyLong(), any(TimeUnit.class)))
+                .thenReturn("ok")
+                .thenReturn("kaboom")
+                .thenAnswer(answersWithDelay(50, invocation -> null));
+
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceived("ok");
+
+        // start the consumer after the queue is trained
+        context.getRouteController().startRoute("foo");
+
+        MockEndpoint.assertIsSatisfied(context);
+
+        verify(kaboomTransaction, timeout(5000)).rollbackTransaction();
+        verify(kaboomTransaction, never()).commitTransaction();
+
+        verify(okTransaction).commitTransaction();
+        verify(okTransaction, never()).rollbackTransaction();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                
from("hazelcast-seda:foo?transacted=true").routeId("foo").autoStartup(false)
+                        
.choice().when(body().isEqualTo("kaboom")).markRollbackOnly().end()
+                        .to("mock:result");
+            }
+        };
+    }
+
+    @AfterEach
+    public final void stopContext() throws Exception {
+        context.stop();
+    }
+}
diff --git a/components/camel-jpa/src/main/docs/jpa-component.adoc 
b/components/camel-jpa/src/main/docs/jpa-component.adoc
index a61fe52350fc..72d7b1e71ffb 100644
--- a/components/camel-jpa/src/main/docs/jpa-component.adoc
+++ b/components/camel-jpa/src/main/docs/jpa-component.adoc
@@ -92,6 +92,13 @@ processed (such as to exclude it from a future query), then 
you can
 annotate a method with `@Consumed` (org.apache.camel.component.jpa.Consumed).
 It will be invoked on your entity bean when the entity bean has been processed 
(and when routing is done).
 
+An entity bean is only deleted (or `@Consumed` invoked) when its exchange 
completed successfully. If the route marks
+the exchange rollback only (for example with `markRollbackOnly()`), the entity 
bean is not consumed and stays in the
+table, so the next poll consumes it again, as long as it still matches the 
query. With `transacted=false` the other
+entity beans of the poll are still consumed, and so is what a `@PreConsumed` 
method changed before routing: an entity
+bean that `@PreConsumed` moved out of the query is not polled again. With 
`transacted=true` the whole poll is rolled
+back, the changes of `@PreConsumed` included.
+
 You can use `@PreConsumed` (org.apache.camel.component.jpa.PreConsumed)
 which will be invoked on your entity bean before it has been processed
 (before routing).
diff --git 
a/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaConsumer.java
 
b/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaConsumer.java
index e55c4bfc5f66..47d50cc691bd 100644
--- 
a/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaConsumer.java
+++ 
b/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaConsumer.java
@@ -36,6 +36,7 @@ import jakarta.persistence.Query;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePropertyKey;
 import org.apache.camel.Processor;
+import org.apache.camel.RollbackExchangeException;
 import org.apache.camel.support.ObjectHelper;
 import org.apache.camel.support.ScheduledBatchPollingConsumer;
 import org.apache.camel.util.AnnotationHelper;
@@ -210,6 +211,18 @@ public class JpaConsumer extends 
ScheduledBatchPollingConsumer {
                     if (exchange.getException() != null) {
                         // if we failed then throw exception
                         throw exchange.getException();
+                    } else if (exchange.isRollbackOnly() || 
exchange.isRollbackOnlyLast()) {
+                        // the route marked the exchange rollback only (there 
is no exception): the entity is not
+                        // consumed, so the next poll consumes it again
+                        if (isTransacted()) {
+                            // throw to roll back the whole batch
+                            // (the exception must be created before the 
exchange is released)
+                            throw new RollbackExchangeException(
+                                    "Rollback transaction due to exchange 
being marked for rollback only", exchange);
+                        }
+                        // not transacted: a deliberate rollback is not an 
error, so skip this entity and continue
+                        // with the next one in the batch
+                        LOG.debug("Exchange marked for rollback only so the 
entity is not consumed: {}", exchange);
                     } else {
                         // Run the @Consumed callback
                         getDeleteHandler().deleteObject(batchEntityManager, 
result, exchange);
@@ -325,6 +338,10 @@ public class JpaConsumer extends 
ScheduledBatchPollingConsumer {
      * This option is default <tt>false</tt>. When <tt>false</tt> then all the 
good messages will commit, and the first
      * failed message will rollback. However when <tt>true</tt>, then all 
messages will rollback, if just one message
      * failed.
+     * <p/>
+     * A message whose exchange was marked rollback only (for example with 
<tt>markRollbackOnly()</tt>) is not consumed:
+     * when <tt>false</tt> the other messages of the batch are still 
committed, when <tt>true</tt> all messages will
+     * rollback.
      */
     public void setTransacted(boolean transacted) {
         this.transacted = transacted;
diff --git 
a/components/camel-jpa/src/test/java/org/apache/camel/component/jpa/JpaConsumerRollbackOnlyTest.java
 
b/components/camel-jpa/src/test/java/org/apache/camel/component/jpa/JpaConsumerRollbackOnlyTest.java
new file mode 100644
index 000000000000..83062f0bc4ee
--- /dev/null
+++ 
b/components/camel-jpa/src/test/java/org/apache/camel/component/jpa/JpaConsumerRollbackOnlyTest.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.jpa;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jakarta.persistence.PersistenceException;
+
+import org.apache.camel.RollbackExchangeException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.examples.MultiSteps;
+import org.apache.camel.examples.SendEmail;
+import org.apache.camel.processor.jpa.AbstractJpaTest;
+import org.apache.camel.util.ObjectHelper;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * An entity whose exchange was marked rollback only (without an exception) 
must not be consumed: the consumer must not
+ * delete it (or call its @Consumed callback), and with transacted=true the 
whole poll must roll back.
+ */
+public class JpaConsumerRollbackOnlyTest extends AbstractJpaTest {
+
+    private static final String SELECT_ALL_STRING = "select x from " + 
SendEmail.class.getName() + " x";
+    private static final String KABOOM = "[email protected]";
+
+    @Test
+    public void testNonTransactedRollbackOnlyEntityIsNotDeleted() throws 
Exception {
+        insertSendEmails("[email protected]", KABOOM, "[email protected]");
+
+        JpaConsumer consumer = (JpaConsumer) 
context.getRoute("non-tx").getConsumer();
+        // one poll in the test thread (the scheduler is not started)
+        assertEquals(3, consumer.poll());
+
+        assertEquals(List.of(KABOOM), sendEmailAddresses(),
+                "only the entity whose exchange was marked rollback only must 
stay in the table");
+        assertEquals(2, getMockEndpoint("mock:result").getReceivedCounter());
+
+        // the rollback only entity is consumed again by the next poll
+        assertEquals(1, consumer.poll());
+        assertEquals(List.of(KABOOM), sendEmailAddresses());
+        assertEquals(4, getMockEndpoint("mock:start").getReceivedCounter());
+    }
+
+    @Test
+    public void testTransactedRollbackOnlyEntityRollsBackThePoll() throws 
Exception {
+        insertSendEmails("[email protected]", KABOOM, "[email protected]");
+
+        JpaConsumer consumer = (JpaConsumer) 
context.getRoute("tx").getConsumer();
+        PersistenceException e = assertThrows(PersistenceException.class, 
consumer::poll,
+                "a rollback only exchange must roll back a transacted poll");
+        
assertNotNull(ObjectHelper.getException(RollbackExchangeException.class, e),
+                "the poll must be rolled back by a RollbackExchangeException");
+
+        assertEquals(List.of("[email protected]", "[email protected]", KABOOM), 
sendEmailAddresses(),
+                "no entity must be deleted when the transacted poll is rolled 
back");
+    }
+
+    @Test
+    public void testNonTransactedRollbackOnlyEntityIsNotConsumedCallback() 
throws Exception {
+        for (String address : List.of("[email protected]", KABOOM, 
"[email protected]")) {
+            saveEntityInDB(new MultiSteps(address));
+        }
+
+        JpaConsumer consumer = (JpaConsumer) 
context.getRoute("consumed").getConsumer();
+        assertEquals(3, consumer.poll());
+
+        entityManager.clear();
+        List<?> step1 = entityManager.createQuery("select x from " + 
MultiSteps.class.getName() + " x where x.step = 1")
+                .getResultList();
+        assertEquals(1, step1.size(), "the @Consumed callback must not be 
called for the rollback only entity");
+        assertEquals(KABOOM, ((MultiSteps) step1.get(0)).getAddress());
+    }
+
+    private void insertSendEmails(String... addresses) {
+        for (String address : addresses) {
+            saveEntityInDB(new SendEmail(address));
+        }
+    }
+
+    private List<String> sendEmailAddresses() {
+        entityManager.clear();
+        List<?> list = 
entityManager.createQuery(SELECT_ALL_STRING).getResultList();
+        List<String> answer = new ArrayList<>();
+        for (Object item : list) {
+            answer.add(((SendEmail) item).getAddress());
+        }
+        answer.sort(null);
+        return answer;
+    }
+
+    @Override
+    protected void cleanupRepository() {
+        super.cleanupRepository();
+        transactionTemplate.execute(status -> {
+            entityManager.joinTransaction();
+            List<?> list = entityManager.createQuery("select x from " + 
MultiSteps.class.getName() + " x").getResultList();
+            for (Object item : list) {
+                entityManager.remove(item);
+            }
+            entityManager.flush();
+            return Boolean.TRUE;
+        });
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("jpa://" + SendEmail.class.getName() + 
"?transacted=false&startScheduler=false").routeId("non-tx")
+                        .to("mock:start")
+                        .choice().when(simple("${body.address} == '" + KABOOM 
+ "'")).markRollbackOnly().end()
+                        .to("mock:result");
+
+                from("jpa://" + SendEmail.class.getName() + 
"?transacted=true&startScheduler=false").routeId("tx")
+                        .choice().when(simple("${body.address} == '" + KABOOM 
+ "'")).markRollbackOnly().end()
+                        .to("mock:result");
+
+                from("jpa://" + MultiSteps.class.getName() + "?query=select x 
from " + MultiSteps.class.getName()
+                     + " x where x.step = 
1&startScheduler=false").routeId("consumed")
+                        .choice().when(simple("${body.address} == '" + KABOOM 
+ "'")).markRollbackOnly().end()
+                        .to("mock:result");
+            }
+        };
+    }
+
+    @Override
+    protected String routeXml() {
+        return "org/apache/camel/processor/jpa/springJpaRouteTest.xml";
+    }
+
+    @Override
+    protected String selectAllString() {
+        return SELECT_ALL_STRING;
+    }
+}
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index 87b8d1a543b6..24d8b1ea2530 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -29,6 +29,22 @@ that a route sends to and no route consumes, so they report 
the same endpoints o
 
 So `camel validate` can report an endpoint it did not report before.
 
+=== camel-jpa, camel-hazelcast - an exchange marked rollback only is not 
consumed
+
+When a route marks the exchange rollback only (for example with 
`markRollbackOnly()` or `markRollbackOnlyLast()`)
+there is no exception on the exchange, and these consumers treated it as a 
success. The JPA consumer deleted the entity
+(or called its `@Consumed` method) and committed the poll, and the transacted 
(`transacted=true`) Hazelcast SEDA
+consumer committed its transaction, so the message was removed from the queue. 
Now a rollback only exchange is not
+consumed: the JPA consumer leaves the entity in the table, so the next poll 
consumes it again, as long as it still
+matches the query. With `transacted=false` the other entities of the poll are 
still consumed (without logging a WARN),
+and so is what a `@PreConsumed` method changed before routing; with 
`transacted=true` the whole poll is rolled back,
+as for a failed exchange. The Hazelcast SEDA consumer rolls back its 
transaction, so the message stays in the queue.
+
+A message that the route marks rollback only every time was removed before, 
and is now consumed again at every poll
+(JPA), or taken from the queue again at once, without a delay (transacted 
Hazelcast SEDA, as for a failed exchange).
+Handle such a message in the route instead, for example by moving it aside, 
rather than marking it rollback only
+every time.
+
 === camel-hashicorp-vault - properties without engine use the `secret` engine
 
 A `hashicorp:` property without an engine, such as `{{hashicorp:mysecret}}` or 
`{{hashicorp:mysecret#field}}`, now

Reply via email to