Skip to content

fix(cli): don't send dynamic IR bodies in registerApiDefinition request - #17426

Open
devin-ai-integration[bot] wants to merge 3 commits into
mainfrom
devin/1786738697-fix-register-api-definition-payload
Open

fix(cli): don't send dynamic IR bodies in registerApiDefinition request#17426
devin-ai-integration[bot] wants to merge 3 commits into
mainfrom
devin/1786738697-fix-register-api-definition-payload

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Description

Docs publishing fails with PAYLOAD_TOO_LARGE / FST_ERR_CTP_BODY_TOO_LARGE (FDR's Fastify bodyLimit is 100 MiB) for large APIs that have dynamic snippets configured for several SDK languages.

publishDocs was sending the full dynamic IR inline for every language in the registerApiDefinition body:

dynamicIRs: dynamicIRsByLanguage // Record<language, { dynamicIR: <entire IR> }>

FDR never reads those bodies — getDynamicIrsUploadsgetPresignedApiDefinitionDynamicIRsUploadUrls iterates the map and ignores the value (for (const [language, _dynamicIr] of ...)), minting one presigned S3 URL per language; the CLI then uploads the IRs directly to S3 via uploadDynamicIRs. So the request body carried one redundant copy of the IR per language on top of the API definition itself, which is what pushed it over the limit.

Now only the language keys are sent ({ python: {}, go: {}, ... }); dynamicIR is optional in the FDR contract (z.unknown()), and the local dynamicIRsByLanguage still holds the bodies for the S3 upload step, so upload behavior is unchanged.

Changes Made

  • Added toRegisterDynamicIRsInput which strips IR bodies while preserving language keys
  • publishDocs uses it for the registerApiDefinition call

Testing

  • Unit tests added/updated (toRegisterDynamicIRsInput.test.ts, 3 passing)
  • turbo compile --filter=@fern-api/remote-workspace-runner and pnpm check:fix clean

Link to Devin session: https://app.devin.ai/sessions/8f61e79cb12c453b8b22dd6809985f1c


Open in Devin Review

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@nitpickybot nitpickybot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review Summary

Small, focused fix: strips dynamic IR bodies from the registerApiDefinition request since FDR only needs the language keys to mint presigned S3 URLs. Logic and tests look correct. Only concern is back-compat with older/self-hosted FDR deployments that might still read the inline IR.

  • 🔵 1 suggestion(s)

Comment on lines +11 to +17
export function toRegisterDynamicIRsInput(
dynamicIRsByLanguage: Record<string, DynamicIr> | undefined
): Record<string, DynamicIr> | undefined {
if (dynamicIRsByLanguage == null) {
return undefined;
}
return Object.fromEntries(Object.keys(dynamicIRsByLanguage).map((language) => [language, {}]));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 suggestion

Worth confirming that no deployed FDR version (including self-hosted registries pinned to older releases) consumes dynamicIRs[lang].dynamicIR from the registration body. If any do, this silently drops their dynamic snippets rather than failing loudly. If the S3 upload path is the only consumer everywhere, ignore.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked this in fern-platform: no FDR version has ever read the IR body from the register request.

  • dynamicIR first appears in FDR source in chore(fdr): separate dynamic ir uploads (31cf0be, fern-platform#3378) — before that the field didn't exist in the register contract at all, so older/self-hosted registries ignore it as an unknown field.
  • Since it was introduced, the only consumer is getDynamicIrsUploadsS3Service.getPresignedApiDefinitionDynamicIRsUploadUrls, which iterates Object.entries(dynamicIRs) and discards the value (for (const [language, _dynamicIr] of ...)) to mint one presigned URL per language. Reads go through loadDynamicIRFromS3, i.e. S3 is the only source of truth.
  • FDR's own registration tests already send dynamicIR: {} (servers/fdr/src/__test__/local/services/api.test.ts), and the schema is z.object({ dynamicIR: z.unknown() }), so an empty object is valid input rather than a validation failure.

So dropping the bodies can't silently lose snippets — a registry that failed to receive the IR would fail at the upload/read step, not silently.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

willkendall01 and others added 2 commits August 14, 2026 20:46
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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.

1 participant