kestra-io / kestra-io/plugin-datahub
Ingestion: a `kestra://` recipe URI supplied as a string is unreachable and throws `ClassCastException`
- Dominant language
- Java
- Stars
- 1
- Forks
- 3
- Avg merge
- 13h 42m
- Merged PRs (30d)
- 3
Description
### Describe the issue
## Summary
`Ingestion` documents `recipe` as accepting either an inline map or a `kestra://` internal-storage URI pointing to a recipe file. But the URI form only works when `recipe` is a `java.net.URI` *object*; a `kestra://…` **string** — the only form a YAML flow can produce — falls through to a `(Map) recipe` cast and throws `ClassCastException` before any ingestion runs. `recipe` is also never rendered.
Found during a documentation audit; docs PR: kestra-io/plugin-datahub#65
## Details
**`src/main/java/io/kestra/plugin/datahub/Ingestion.java`**
`run()` calls `getRecipe()` as its first statement, and `getRecipe()` only treats a `URI` object as a storage URI:
```java
private String getRecipe(RunContext runContext) throws Exception {
File tempFile = runContext.workingDir().createTempFile(".yml").toFile();
Map yaml;
if (this.recipe instanceof URI from) { // only a java.net.URI OBJECT
...
yaml = MAPPER.readValue(runContext.storage().getFile(from), ...);
} else {
yaml = (Map) recipe; // String -> ClassCastException
}
...
}
```
- `recipe` (L113-115) is `@PluginProperty(group = "main")` **without** `dynamic = true`, and is never `runContext.render(this.recipe)`-ed.
- A YAML value like `recipe: "{{ outputs.write.uri }}"` or `recipe: "{{ input('recipe_file') }}"` deserializes to a `String`, not a `URI`, so it hits the `else` branch and throws `ClassCastException`.
## Impact
- The documented "recipe as a `kestra://` URI / recipe file" mode is unreachable from a normal flow — it fails with a raw `ClassCastException`.
- Because `recipe` is not `dynamic` and never rendered, Pebble expressions passed as/within `recipe` (including secrets embedded in an inline recipe map) may not be resolved.
## Suggested fix
- In `getRecipe()`, detect a `kestra://` **string** prefix and read it from internal storage (as the sibling plugins do), in addition to the `URI` object case.
- Consider marking `recipe` `dynamic = true` and rendering it so templated values resolve.
## Verification
Reproduced by a unit test that passes `recipe` as a `kestra://` string (what YAML produces) and asserts the `ClassCastException` — no DocumentDB/Docker required, throws in `getRecipe()` before any external call. Passes against current `main`:
```java
package io.kestra.plugin.datahub;
import com.google.common.collect.ImmutableMap;
import io.kestra.core.junit.annotations.KestraTest;
import io.kestra.core.runners.RunContext;
import io.kestra.core.runners.RunContextFactory;
import io.kestra.core.utils.TestsUtils;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertThrows;
@KestraTest
class DocReviewBugVerificationTest {
@Inject
private RunContextFactory runContextFactory;
@Test
void recipeAsKestraUriString_throwsClassCastException() {
Ingestion task = Ingestion.builder()
.id("unit-test")
.type(Ingestion.class.getName())
.recipe("kestra:///some/namespace/recipe.yml") // String, as YAML renders a kestra:// URI to
.build();
RunContext runContext = TestsUtils.mockRunContext(runContextFactory, task, ImmutableMap.of());
ClassCastException exception = assertThrows(ClassCastException.class, () -> task.run(runContext));
assertThat(exception.getMessage(), containsString("String"));
}
}
```
Note: the existing `IngestionTest.runWithRecipeFile` passes a `URI` *object* returned by `storageInterface.put(...)`, which is why the "recipe file" path works in tests but not from a real flow.
### Environment
- Kestra Version: develop
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with src/main/java/io/kestra/plugin/datahub/Ingestion.java, especially getRecipe() and the recipe property around L113-L115. Compare the existing IngestionTest.runWithRecipeFile path with the supplied DocReviewBugVerificationTest, then verify that a YAML-produced kestra:// string no longer reaches the Map cast and that the existing URI-object test still passes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100