#364 dataRepository.getContent rejects string type in production but docs and testing helper demonstrate strings
Opened by jentz · 5/16/2026· Shipped 5/18/2026
Summary
In a workflow-scope report's execute(context), the documented way to
read step-execution data is
context.dataRepository.getContent(type, modelId, dataName, version?).
The skill references describe type as the model type string
(e.g. "aws/ec2"), and the testing helper accepts a string. But at
runtime the production data repository expects a ModelType object
with a .toDirectoryPath() method, and rejects strings with:
TypeError: type.toDirectoryPath is not a functionThere is no documented helper for constructing a ModelType from a
string in the report-context API surface, and
definitionRepository.findById(modelId) does not resolve to a usable
object in workflow scope (it returns silently, no warning, no error).
This makes getContent effectively unusable in workflow-scope reports
that follow the documented patterns — they have to bypass the API and
read raw files from disk.
Where (the contradiction)
The swamp-report skill's testing reference shows strings:
// Read raw bytes and parse — same pattern as live reports
const raw = await context.dataRepository.getContent(
"aws/ec2", // <- string
"my-ec2",
"state-current",
1,
);report-types.md also implies strings via the parameter-mapping
table:
| Parameter | Value |
|---|---|
type |
context.modelType |
For workflow scope, report-types.md says:
For workflow-scope reports, use
step.modelType,step.modelId, andstep.dataHandlesfromcontext.stepExecutions.
…and step.modelType is typed as string in the same reference:
stepExecutions: Array<{
jobName: string;
stepName: string;
modelName: string;
modelType: string; // <- string
...
}>So both the parameter-mapping table and the typed shape of
stepExecutions[].modelType say strings.
Production runtime says objects. Calling getContent with the
string value of step.modelType throws
type.toDirectoryPath is not a function.
Reproduction
Create a workflow-scope report extension whose
executeiteratescontext.stepExecutionsand callsawait context.dataRepository.getContent( step.modelType, // string per report-types.md step.modelId, handle.name, handle.version, );
Run a workflow that produces step outputs and triggers the report.
Observe:
TypeError: type.toDirectoryPath is not a functionat the call site.
Encountered while building a workflow-scope audit report against
swamp 20260516.045246.0-sha.e6eda98d.
Expected
Either:
dataRepository.getContentaccepts a string for thetypeparameter (matches docs and testing helper), or- the docs and testing helper are updated to require a
ModelTypeobject, and a constructor/helper (e.g.ModelType.fromString(step.modelType)orcontext.parseModelType(step.modelType)) is exposed on the report context.
Actual
getContent(string, ...) throws synchronously inside the production
data repository on the first attempt to read step data. The error is
not caught or wrapped, so it bubbles up as an unhandled exception
during report execution.
Confounder: the testing helper (@systeminit/swamp-testing's
createReportTestContext) accepts strings — so unit tests pass against
the documented contract, and the breakage only surfaces against the
real runtime.
Impact
- Workflow-scope reports that need to read step data must bypass the
documented API and read raw files from disk
(
<repoDir>/.swamp/data/<type>/<id>/<name>/<v>/raw). - The path layout is stable per the swamp-extension skill's docs, so this works — but it duplicates the responsibility of the data repository and breaks if swamp ever changes the on-disk format.
- Unit tests written against the testing helper give false confidence: they pass with strings, then the live workflow throws.
Workaround
Reading the file directly:
async function readDataFile(
context: any,
modelType: string,
modelId: string,
dataName: string,
version: number,
): Promise<Uint8Array | null> {
const path =
`${context.repoDir}/.swamp/data/${modelType}/${modelId}/${dataName}/${version}/raw`;
try {
return await Deno.readFile(path);
} catch (err) {
if (err instanceof Deno.errors.NotFound) return null;
throw err;
}
}This works because context.repoDir, the directory layout, and
step.modelType as a string are all stable across the production
runtime. It's a workaround, not a fix — third-party code shouldn't
need to know the on-disk layout.
Suggested resolutions (any one is sufficient)
Accept strings. Make the production
getContentcoerce strings into the internalModelTyperepresentation. This matches docs and the testing helper. Smallest change.Expose a parser. Add
parseModelType(string)(orModelType.fromString(string)) on the report-context API and update the docs + testing helper to require an object. Larger change but explicit.Hand workflow-scope steps a typed object. Change
stepExecutions[].modelTypefromstringto the sameModelTypeobject shape used in method/model scope. Cleanest mental model long-term — but a breaking change for existing reports that readstep.modelTypeas a string for logging/filtering (defensive.toString?.()fallbacks would no longer be needed).
The first option is least disruptive; the third is cleanest long-term.
Environment
- swamp
20260516.045246.0-sha.e6eda98d - Workflow-scope report (
scope: "workflow") - macOS 25.4.0 / Deno bundled with swamp
Shipped
Click a lifecycle step above to view its details.
Sign in to post a ripple.