[Bug]: Subcontracting: SetIsSubcontracting calls CurrPage.Update() with SaveRecord = true from OnAfterGetCurrRecord, aborting the Transfer Order page
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 76/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Domain
- frontend
Research direction
Inspect src/Apps/W1/Subcontracting/App/src/Transfer/SubcTransOrderSub.PageExt.al at SetIsSubcontracting and its caller in SubcTransferOrder.PageExt.al. Confirm the page refresh does not save the record, then replay 00_Repro_Setup.yml and 01_Repro_R1_Release.yml on the stated Business Central environments; Release and Create Whse. Shipment should complete without either Transfer Line error.
Written by the indexing model from the issue text.
Description
Describe the issue
On the Transfer Order page, Subc. Trans. Order Sub. (PageExtension 20529) forces a saving page update from inside a record-fetch trigger. That aborts the page during the normal transfer document flow.
The statement
internal procedure SetIsSubcontracting(IsSubcontractingRelated: Boolean)
begin
HasSubcontractingContext := IsSubcontractingRelated;
CurrPage.Update(); // SaveRecord defaults to true
end;
CurrPage.Update() with no argument is CurrPage.Update(true), so it saves the record. The procedure only assigns a visibility Boolean, so there is nothing that needs saving.
The caller
trigger OnAfterGetCurrRecord()
begin
#if not CLEAN29
if not SubcontractingEnabled then
exit;
#endif
ShowSubcontractingFactBox := SubcTransferManagement.IsSubcontractingTransferDocument(Rec);
CurrPage.TransferLines.Page.SetIsSubcontracting(ShowSubcontractingFactBox);
end;
OnAfterGetCurrRecord fires on every current-record refresh, including moments when the subform line is not in a clean committed state. The forced save then fails in one of two ways:
- Brand-new subform line,
Line No.not yet assigned. The platform resolves the save as a rename, which reachesTable 5741 "Transfer Line".OnRename- an unconditionalError. A Transfer Line can never be renamed, so the abort is guaranteed. - Existing line whose page copy is older than the stored record. Optimistic concurrency rejects the write.
Observed errors
Business Central 29.0.54011, India (IN) localisation, clean sandbox, no third-party extensions installed.
Variant A - uncommitted line:
You cannot rename a Transfer Line
Microsoft.Dynamics.Nav.Runtime.FormAbortException: Page Transfer Order has to close
Variant B - committed line, stale page copy:
The changes to the Transfer Line record cannot be saved because some information on the
page is not up-to-date. Close the page, reopen it, and try again.
Identification fields and values: Document No.='1006', Line No.='10000'
Call stack
Copied from the client's Share details pane. Identical for both variants, two frames, both in this extension.
"Subc. Trans. Order Sub."(PageExtension 20529).SetIsSubcontracting line 3
- Subcontracting by Microsoft version 29.0.54011.54955
"Subc. Transfer Order"(PageExtension 20526).OnAfterGetCurrRecord(Trigger) line 8
- Subcontracting by Microsoft version 29.0.54011.54955
SetIsSubcontracting line 3 is the CurrPage.Update() statement. The trigger's reported line 8 does not line up with line 8 of the source above because the #if not CLEAN29 directives are compiled out of the shipped artifact; line 8 in the compiled object is the SetIsSubcontracting call.
IN localisation, no third-party extensions. Release itself succeeded here and the failure landed on the next action, which is why we say the trigger, not the action, is the cause.
One more observation
The subform's own OnAfterGetCurrRecord guards itself against repeated work:
local procedure SetSubcontractingVisibility()
begin
if Rec."Document No." = TransferHeader."No." then
exit;
The call arriving from the parent page has no equivalent guard, so SetIsSubcontracting and its forced save run on every refresh.
Expected behavior
Adding a line to a Transfer Order and then invoking Release, or Create Whse. Shipment, should complete normally: the order is released and the warehouse shipment is created. No extension should force a saving page update from a record-fetch trigger.
SetIsSubcontracting assigns a visibility Boolean and nothing else, so it should refresh the page without writing the record:
internal procedure SetIsSubcontracting(IsSubcontractingRelated: Boolean)
begin
HasSubcontractingContext := IsSubcontractingRelated;
- CurrPage.Update();
+ CurrPage.Update(false);
end;
CurrPage.Update(false) redraws the page and re-evaluates the Visible properties bound to HasSubcontractingContext, which is all this procedure needs. It cannot trigger a write, so neither failure mode can occur.
Steps to reproduce
About two minutes. No item tracking, no extensions, no special configuration.
- Provision a Business Central 29.0.54011 sandbox on the IN (India) localisation, standard CRONUS, with no third-party apps installed.
- Open Transfer Orders and choose New.
- Set Transfer-from Code, Transfer-to Code and In-Transit Code. On CRONUS IN:
EAST,WEST,OUT. LOG. - On the lines subform, enter an Item No. (for example
1896-S) and Quantity10. - Without changing focus after typing the quantity, click Release.
- Then click Create Whse. Shipment.
The error appears at step 5 or step 6. Which one you get depends only on whether the subform line had already been committed when the trigger fired; both come from the same code path and produce the same call stack.
Tested on artifacts 29.0.54011.54884, .54955, .55000 and .55007. Present on IN in all of them, including the newest.
Additional context
Why it surfaces only on IN
We ran the same automated suite of 1435 tests twice from one pipeline, minutes apart, against the same artifact sandbox/29.0.54011.55007, with the localisation as the only difference:
| Localisation | Result |
|---|---|
| W1 / base | 1435 tests, 0 failures |
| IN | 1435 tests, 6 failures - every one with the error and call stack above |
Same split on artifact .54884. We also reproduced it by hand in the web client on IN and confirmed it passing on W1, using byte-identical BC Page Scripting recordings that create every object they touch, which rules out demo data and configuration.
W1 / base. The same two recordings, byte for byte, complete without errors.
The Subcontracting app is installed on both localisations - on W1 it is listed in Extension Management as published Global and installed - so the presence of the app is not the discriminator.
Our reading of the gate
The likely gate is the #if not CLEAN29 guard in PageExtension 20526:
#if not CLEAN29
if not SubcontractingEnabled then
exit;
#endif
SubcontractingEnabled comes from Subc. Feature Flag Handler.IsSubcontractingEnabled(), which returns not ManufacturingSetup."Legacy Subcontracting". So on a company where Legacy Subcontracting is still on, the trigger exits at the guard and the bug is invisible; where it is off, the forced save runs. That would make this a demo-data difference rather than localised code.
We have not confirmed the flag's value on each localisation, so please treat that as our reading rather than as established.
It also means the guard disappears entirely once CLEAN29 is defined, at which point the forced save runs unconditionally on every localisation.
Attached: the Page Scripting recordings
I have attached the two BC Page Scripting recordings we used -
00_Repro_Setup.yml
01_Repro_R1_Release.yml
| File | What it does |
|---|---|
00_Repro_Setup.yml |
Creates everything the repro needs, from base functionality only: an item tracking code, an item, and three locations (from, to, and in-transit). Run once per container. |
01_Repro_R1_Release.yml |
Creates the transfer order and its line, invokes Release and then Create Whse. Shipment, and validates the resulting warehouse shipment line. |
Both use base objects only and create every object they touch, so the same two files run unchanged on any localisation with no demo-data dependency. Import them through the Page Scripting pane in the web client (Preview feature) and replay.
On IN the second script stops at Release or at Create Whse. Shipment. On W1 it runs to the end with every validation passing. That is the comparison shown in the two screenshots above.
Impact
Releasing a transfer order and creating its warehouse shipment is core inventory functionality, and this reproduces with a stock item, stock locations, no item tracking and no extensions, so it is not configuration-dependent. It also breaks any partner or ISV extension that drives the Transfer Order page on an affected company.
We have the two BC Page Scripting .yml recordings that reproduce it in a single run, plus the full client error details including session and activity IDs. Happy to attach any of it on request.
I will provide a fix for a bug
- I will provide a fix for a bug
- Dominant language
- AL
- Stars
- 683
- Forks
- 459
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 510
Getting set up
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from microsoft/BCApps
-
Approved ext-ready-to-implement request-for-external Team: Finance
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
microsoft/BCApps#12069 · 1 comment ·
Maintainers usually reply within 1 day
-
Approved request-for-external Team: SCM
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
microsoft/BCApps#12033 · 1 comment ·
Maintainers usually reply within 1 day
-
Approved request-for-external Team: SCM
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
microsoft/BCApps#12032 · 1 comment ·
Maintainers usually reply within 1 day
-
Team: SCM
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
microsoft/BCApps#12012 · 1 comment ·
Maintainers usually reply within 1 day
-
Approved Ownership: Needs Review Team: Other
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
microsoft/BCApps#11800 · 1 comment ·
Maintainers usually reply within 1 day
All issues in microsoft/BCApps
Similar issues
-
Add google analyticsOpen
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
NCAR/music-box-interactive#628 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
phoenixframework/phoenix_live_view#4456 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
USACE/chart-docs#756 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day