You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The API explains what is wrong in reason, but the CLI only prints message, so people see a generic error and cannot fix their command.
Found while dogfooding builtin/extract-text for the documents blog post:
$ npx -y @transloadit/node assemblies create --template builtin/extract-text \ --field text_format=md --field text_granularity=page -i report.pdf -o out/err API error (HTTP 400) INVALID_FORM_DATA: The form contained bad data, which cannot be parsed. https://api2-….transloadit.com/assemblies/<assembly-id>
The Assembly Status for that same request carries the actual cause:
{
"error": "INVALID_FORM_DATA",
"message": "The form contained bad data, which cannot be parsed.",
"reason": "Invalid Builtin Template field “fields.text_granularity”: The page text_granularity is only supported for native text extraction."
}
With the reason on screen the fix is obvious (add --field text_method=native). Without it, "The form contained bad data" points at the upload, not at a field.
What
ApiError builds its message from error, message and assembly_ssl_url only (packages/node/src/ApiError.ts). reason is stored on the error but never shown.
formatAPIError in packages/node/src/cli/helpers.ts prints err.message, so every CLI command drops the reason.
Suggested: have the CLI's formatAPIError append a string reason when the API sent one (and keep structured rawReason out of the one-line output). Whether ApiError.message itself should also include it is a separate call, since SDK users may match on the message.
Done when
The command above prints the reason, and a test covers an API error with and without a reason.
A second case of the same problem, found on 2026-11-11 while storing blog figures.
$ npx -y @transloadit/node storage store press-kit-page.jpg blog/2026-11-llm-ready-markdown/ --workspace my-app --public --jsonWorkspace verification failed (HTTP 400). Check the Storage API … dam:read or dam:write scope.
The Auth Key had the right scopes. Calling the API directly showed the real reason:
INVALID_SIGNATURE: Sign DAM requests for their method and path, in auth.method and auth.path.
So the CLI replaced a precise, actionable API message with a guess about scopes that sent me in the wrong direction. Showing the API's error and message next to (or instead of) the hint would have made this a one-minute diagnosis.
Separate from the reporting problem: the cause here is that production now requires method/path-bound signatures on /dam/* (api2#11023, merged 2026-11-09), while the SDK change that sends them (#648) is not merged or released yet. Until it is, Storage commands in @transloadit/node 6.7.0 and older fail this way in production.
The cause of this second case is fixed in @transloadit/node@6.8.0 (#648): Storage requests now sign their method and path. Checked against production on 2026-11-12: storage ls fails with 6.7.0 and works with 6.8.0. The subject of this issue is unchanged: with 6.7.0 the CLI still printed only “Storage listing failed (HTTP 400)” and not the reason the API gave.
Activity
kvz commentedon Nov 11, 2026
A second case of the same problem, found on 2026-11-11 while storing blog figures.
The Auth Key had the right scopes. Calling the API directly showed the real reason:
So the CLI replaced a precise, actionable API message with a guess about scopes that sent me in the wrong direction. Showing the API's
errorandmessagenext to (or instead of) the hint would have made this a one-minute diagnosis.Separate from the reporting problem: the cause here is that production now requires method/path-bound signatures on
/dam/*(api2#11023, merged 2026-11-09), while the SDK change that sends them (#648) is not merged or released yet. Until it is, Storage commands in@transloadit/node6.7.0 and older fail this way in production.kvz commentedon Nov 12, 2026
The cause of this second case is fixed in
@transloadit/node@6.8.0(#648): Storage requests now sign their method and path. Checked against production on 2026-11-12:storage lsfails with 6.7.0 and works with 6.8.0. The subject of this issue is unchanged: with 6.7.0 the CLI still printed only “Storage listing failed (HTTP 400)” and not the reason the API gave.