Skip to content

[rust-axum] fix: box recursive model fields - #25296

Merged
wing328 merged 2 commits into
OpenAPITools:masterfrom
teovillanueva:fix/rust-axum-box-recursive-models
Oct 27, 2026
Merged

wing328 merged 2 commits into
OpenAPITools:masterfrom
teovillanueva:fix/rust-axum-box-recursive-models

Conversation

@teovillanueva

@teovillanueva teovillanueva commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #25295

rust-axum generates model fields that hold another model without any indirection. When a model leads back to itself, the generated type has infinite size and the crate fails to compile with E0072. Examples: parent: Node; a nullable self reference via anyOf/oneOf with null or nullable + allOf; a cycle such as Employee -> Department -> Employee; or a cycle through a oneOf enum such as Circle.inner -> Shape -> Circle.

Changes

  • New option boxRecursiveModels (default false). Without it the generated code is exactly what master produces today; with it, the boxing below is applied.
  • RustAxumServerCodegen.postProcessAllModels: checks every struct field that holds a model directly (not inside a container). If that model can lead back to the current one, the field gets x-is-boxed. The check follows direct model fields and the oneOf/anyOf variants of enum models.
  • models.mustache: for x-is-boxed fields, wraps the type in Box<...> in the struct field and in new(), and boxes the parsed value in the FromStr implementation.
  • Non-recursive fields are not changed. All existing rust-axum samples are byte-identical after regeneration.
  • New spec 3_1/rust-axum/rust-axum-recursive-models.yaml and sample config rust-axum-recursive-models (with boxRecursiveModels: true).

Not covered

Testing

  • New RustAxumServerCodegenTest#testRecursiveModelFieldsAreBoxed. It checks direct, nullable (anyOf/oneOf null), indirect and oneOf-variant recursion. It also checks that Vec and non-recursive references are not boxed. The test fails without the fix.
  • New RustAxumServerCodegenTest#testRecursiveModelFieldsAreNotBoxedByDefault: without the option, nothing is boxed.
  • mvn integration-test -f samples/server/petstore/rust-axum/pom.xml passes.
  • New sample samples/server/petstore/rust-axum/output/rust-axum-recursive-models. These pass on it: cargo build --all-targets --all-features, cargo build --all-targets --no-default-features, cargo test, cargo clippy --all-targets --all-features. Before the fix, the same spec fails cargo check with E0072.

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    Regenerated all rust-axum samples with RUST_POST_PROCESS_FILE=$PWD/samples/server/petstore/rust-axum/rustfmt-2021.sh ./bin/generate-samples.sh bin/configs/manual/rust-axum* (17 configs, including the new rust-axum-recursive-models). The only change is the new sample. docs/generators/rust-axum.md was regenerated with export_docs_generators.sh for the new option.
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

cc @frol @farcaller @richardwhiuk @paladinzh @jacob-pro @dsteeley


Summary by cubic

Fixes recursive model fields in the rust-axum generator so models that reference themselves, directly or through other models, compile without E0072. Fields that would create an infinitely sized type are now wrapped in Box<...> behind the new boxRecursiveModels option (default false), so existing generated code stays byte-identical.

  • Detects cycles in postProcessAllModels and marks the offending fields with x-is-boxed.
  • Updates models.mustache to emit Box<...> for those fields in the struct, new(), and FromStr.
  • Only direct model references are boxed; containers like Vec and non-recursive references are unchanged.
  • Adds a new sample (rust-axum-recursive-models) and unit tests covering direct, nullable, indirect, and oneOf recursion.

Written for commit 92e3fdc. Summary will update on new commits.

View guided diff

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 18 files

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

@wing328

wing328 commented Oct 19, 2026

Copy link
Copy Markdown
Member

Thanks for the PR

cc @linxGnu for review

Comment on lines +1443 to +1461

// Model fields that lead back to their own model (directly or through other models)
// would make the struct infinitely sized, so they are boxed.
final Map<String, CodegenModel> models = new HashMap<>();
for (ModelsMap modelsMap : objs.values()) {
for (ModelMap mo : modelsMap.getModels()) {
models.put(mo.getModel().classname, mo.getModel());
}
}

for (CodegenModel cm : models.values()) {
for (CodegenProperty var : cm.vars) {
final String target = directModelReference(var);
if (target != null && reachesModel(target, cm.classname, models, new HashSet<>())) {
var.vendorExtensions.put("x-is-boxed", true);
}
}
}

@linxGnu linxGnu Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@teovillanueva
Hi, I don't want to break existing generated code. Please feature-gate it throughout additionalProperties

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.

Done in 92e3fdc: the boxing is now behind a new boxRecursiveModels option (default false), so without it the generated code is the same as on master. The new rust-axum-recursive-models sample enables it, there is a test for each case, the docs are regenerated, and the integration tests pass.

@linxGnu linxGnu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM. Thank you for contributing to Rust-Axum @teovillanueva

cc @wing328 to merge this PR

@wing328
wing328 merged commit bf51cab into OpenAPITools:master Oct 27, 2026
18 checks passed
@wing328 wing328 added this to the 7.27.0 milestone Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG][rust-axum] Recursive models generate infinitely sized types (E0072)

3 participants