Fix CustomOp forward compatibility: cap version instead of rejecting#29574
Merged
Conversation
Remove the blanket version check in CustomOpKernel that prevented custom ops compiled against a newer ORT from loading on an older runtime. Instead, cap the version passed to GetApi() at ORT_API_VERSION. This aligns custom ops with the EP plugin ABI pattern where forward compatibility is supported via runtime version detection. Individual newer functions in OrtCustomOp (CreateKernelV2, InferOutputShapeFn, GetMayInplace, etc.) are already gated by per-function version checks throughout custom_ops.cc, making the blanket reject both redundant and harmful. The EP is responsible for not calling API functions newer than the runtime version -- the same contract as the EP plugin interface. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Test that a custom op with OrtCustomOp::version > ORT_API_VERSION can be registered and executed. This simulates the forward compatibility scenario where an IHV EP compiled against a newer ORT is loaded into an older runtime. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The MyCustomKernel::Compute tries to get an arena allocator which may not be available in all CI configurations. Since the fix being tested is in CustomOpKernel construction (version capping), session creation is sufficient to exercise the relevant code path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
sanaa-hamel-microsoft
previously approved these changes
Jul 7, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adjusts custom-op loading behavior to improve forward compatibility: instead of rejecting custom ops whose OrtCustomOp::version is higher than the runtime’s ORT_API_VERSION, the runtime now caps the version used when selecting the OrtApi* passed into custom-op callbacks.
Changes:
- Update
CustomOpKernelconstruction to useGetApi(min(op.version, ORT_API_VERSION))rather than rejecting newer versions. - Add a C API test that simulates a “newer-compiled” custom op by setting
custom_op.version = ORT_API_VERSION + 1and verifying session creation succeeds. - Update
OrtCustomOp::versionheader comment to document the capping behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| onnxruntime/core/session/custom_ops.cc | Caps the API version used for OrtGetApiBase()->GetApi(...) during custom kernel creation to enable forward compatibility. |
| onnxruntime/test/shared_lib/test_inference.cc | Adds a regression test covering forward-compat custom-op loading (session creation path). |
| include/onnxruntime/core/session/onnxruntime_c_api.h | Updates the OrtCustomOp::version documentation to reflect new runtime behavior. |
edgchen1
reviewed
Jul 7, 2026
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
edgchen1
approved these changes
Jul 7, 2026
tianleiwu
pushed a commit
that referenced
this pull request
Jul 7, 2026
…29574) ### Description Remove the blanket version check in CustomOpKernel that prevented custom ops compiled against a newer ORT from loading on an older runtime. Instead, cap the version passed to GetApi() at ORT_API_VERSION. This aligns custom ops with the EP plugin ABI pattern where forward compatibility is supported via runtime version detection. Individual newer functions in OrtCustomOp (CreateKernelV2, InferOutputShapeFn, GetMayInplace, etc.) are already gated by per-function version checks throughout custom_ops.cc, making the blanket reject both redundant and harmful. The EP is responsible for not calling API functions newer than the runtime version -- the same contract as the EP plugin interface. ### Motivation and Context <!-- - Why is this change required? What problem does it solve? - If it fixes an open issue, please link to the issue here. --> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
tianleiwu
added a commit
that referenced
this pull request
Jul 9, 2026
This cherry-picks the following commits for the release: | Commit ID | PR Number | Commit Title | |-----------|-----------|-------------| | 56f6fee | #29038 | [CUDA] QMoE GEMV fast path for batch-1 decode | | a2c7c3b | #29081 | Fix QMoE CPU livelock by eliminating nested intra-op parallelism | | bd0cb9a | #28571 | [MLAS] KleidiAI fix igemm regression | | 5eb4aee | #29574 | Fix CustomOp forward compatibility: cap version instead of rejecting | | 5f49a37 | #29274 | fix(ci): incorrect identity for azcopy | | bb9ba7e | #29468 | Upgrade to Xcode 26 | | 36c6b7e | #29450 | Fix brew install applesimutils failure by trusting wix/brew tap | | a491809 | #29575 | Don't echo command when setting VSO variable in mac-cpu-packing-jobs.yml. | | a06675e | #29609 | Fix web e2e (npm/vite) and Python DML CI pipelines | Also fixed version missed by version update script. --------- Signed-off-by: Qxiang Xu <Qixiang.Xu@arm.com> Signed-off-by: Jonathan Clohessy <Jonathan.Clohessy@arm.com> Signed-off-by: Martin Klacer <martin.klacer@arm.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: tlwu <tlwu@example.com> Co-authored-by: Martin Klacer <martin.klacer@arm.com> Co-authored-by: Jonathan Clohessy <Jonathan.Clohessy@arm.com> Co-authored-by: Damien Dooley <damien.dooley@arm.com> Co-authored-by: Chi Lo <54722500+chilo-ms@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Sanaa Hamel <sanaahamel@microsoft.com> Co-authored-by: Edward Chen <18449977+edgchen1@users.noreply.github.com>
This was referenced Jul 11, 2026
This was referenced Jul 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Remove the blanket version check in CustomOpKernel that prevented custom ops compiled against a newer ORT from loading on an older runtime. Instead, cap the version passed to GetApi() at ORT_API_VERSION.
This aligns custom ops with the EP plugin ABI pattern where forward compatibility is supported via runtime version detection. Individual newer functions in OrtCustomOp (CreateKernelV2, InferOutputShapeFn, GetMayInplace, etc.) are already gated by per-function version checks throughout custom_ops.cc, making the blanket reject both redundant and harmful.
The EP is responsible for not calling API functions newer than the runtime version -- the same contract as the EP plugin interface.
Motivation and Context