•  
      request #44484 Unable to update an artefact that use an 'Artefact link' field
    Infos
    #44484
    Aurélien Tisné (atisne)
    2025-09-10 11:26
    2025-09-04 11:11
    46186
    Details
    Unable to update an artefact that use an 'Artefact link' field

    After upgrading to Tuleap 16.11, we are facing to an issue concerning the new 'Artifact link' field. The update of some artefacts fails with an Internal serveur error:

    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: PHP Fatal error:  Uncaught TypeError: Tuleap\Tracker\Artifact\Changeset\ArtifactLink\SubmittedValueConvertor::convert(): Argument #1 ($submitted_value) must be of type array, string given, c>
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: Stack trace:
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #0 /usr/share/tuleap/plugins/tracker/include/FormElement/Field/ArtifactLink/ArtifactLinkField.php(1398): Tuleap\Tracker\Artifact\Changeset\ArtifactLink\SubmittedValueConvertor->convert()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #1 /usr/share/tuleap/plugins/tracker/include/Workflow/WorkflowUpdateChecker.php(71): Tuleap\Tracker\FormElement\Field\ArtifactLink\ArtifactLinkField->hasChanges()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #2 /usr/share/tuleap/plugins/tracker/include/Workflow/WorkflowUpdateChecker.php(50): Tuleap\Tracker\Workflow\WorkflowUpdateChecker->fieldHasChanges()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #3 /usr/share/tuleap/plugins/tracker/include/Tracker/Artifact/Changeset/NewChangesetFieldsValidator.php(61): Tuleap\Tracker\Workflow\WorkflowUpdateChecker->canFieldBeUpdated()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #4 /usr/share/tuleap/plugins/tracker/include/Tracker/Artifact/Changeset/FieldsValidator.php(89): Tracker_Artifact_Changeset_NewChangesetFieldsValidator->validateField()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #5 /usr/share/tuleap/plugins/tracker/include/Tracker/Artifact/Changeset/FieldsValidator.php(64): Tracker_Artifact_Changeset_FieldsValidator->validateOneField()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #6 /usr/share/tuleap/plugins/tracker/include/Tracker/Artifact/Changeset/NewChangesetValidator.php(59): Tracker_Artifact_Changeset_FieldsValidator->validate()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #7 /usr/share/tuleap/plugins/tracker/include/Tracker/Artifact/Changeset/NewChangesetCreator.php(72): Tuleap\Tracker\Artifact\Changeset\NewChangesetValidator->validateNewChangeset()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #8 /usr/share/tuleap/src/vendor/paragonie/easydb/src/EasyDB.php(1263): Tuleap\Tracker\Artifact\Changeset\NewChangesetCreator->{closure:Tuleap\Tracker\Artifact\Changeset\NewChangesetCreator::>
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #9 /usr/share/tuleap/src/common/DB/DBTransactionExecutorWithConnection.php(44): ParagonIE\EasyDB\EasyDB->tryFlatTransaction()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #10 /usr/share/tuleap/plugins/tracker/include/Tracker/Artifact/Changeset/NewChangesetCreator.php(61): Tuleap\DB\DBTransactionExecutorWithConnection->execute()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #11 /usr/share/tuleap/plugins/tracker/include/Tracker/Artifact/Link/ArtifactReverseLinksUpdater.php(117): Tuleap\Tracker\Artifact\Changeset\NewChangesetCreator->create()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #12 /usr/share/tuleap/plugins/tracker/include/Tracker/Artifact/Link/ArtifactReverseLinksUpdater.php(93): Tuleap\Tracker\Artifact\Link\ArtifactReverseLinksUpdater->saveChangesets()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #13 /usr/share/tuleap/src/common/NeverThrow/Ok.php(70): Tuleap\Tracker\Artifact\Link\ArtifactReverseLinksUpdater->{closure:Tuleap\Tracker\Artifact\Link\ArtifactReverseLinksUpdater::updateArt>
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #14 /usr/share/tuleap/plugins/tracker/include/Tracker/Artifact/Link/ArtifactReverseLinksUpdater.php(93): Tuleap\NeverThrow\Ok->andThen()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #15 /usr/share/tuleap/plugins/tracker/include/Action/UpdateArtifactAction.php(108): Tuleap\Tracker\Artifact\Link\ArtifactReverseLinksUpdater->updateArtifactAndItsLinks()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #16 /usr/share/tuleap/plugins/tracker/include/Tracker/Artifact/Artifact.php(950): Tuleap\Tracker\Action\UpdateArtifactAction->process()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #17 /usr/share/tuleap/plugins/tracker/include/Tracker/TrackerManager.php(116): Tuleap\Tracker\Artifact\Artifact->process()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #18 /usr/share/tuleap/plugins/tracker/include/Tracker/TrackerManager.php(169): TrackerManager->processSubElement()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #19 /usr/share/tuleap/plugins/tracker/include/TrackerPluginDefaultController.php(45): TrackerManager->process()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #20 /usr/share/tuleap/src/common/Request/FrontRouter.php(251): Tuleap\Tracker\TrackerPluginDefaultController->process()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #21 /usr/share/tuleap/src/common/Request/FrontRouter.php(109): Tuleap\Request\FrontRouter->routeHandler()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #22 /usr/share/tuleap/src/www/index.php(50): Tuleap\Request\FrontRouter->route()
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]: #23 {main}
    sept. 02 14:06:23 tuleap.c-s.fr php[4020142]:   thrown in /usr/share/tuleap/plugins/tracker/include/Artifact/Changeset/ArtifactLink/SubmittedValueConvertor.php on line 58
    

    We noticed that, with an artefact that have no issue, the first argument of the method convert() is an Array like

    Array
    (
        [new_values] =>
        [removed_values] => Array
            (
            )
    
        [list_of_artifactlinkinfo] => Array
            (
                [3667] => Tracker_ArtifactLinkInfo Object
                    (
                        [artifact_id:protected] => 3667
                        [keyword:protected] => FT
                        [group_id:protected] => 174
                        [tracker_id:protected] => 405
                        [last_changeset_id:protected] => 47936
                        [type:Tracker_ArtifactLinkInfo:private] => failed
                        [artifact:Tracker_ArtifactLinkInfo:private] =>
                    )
    
            )
    
    )
    

    But, with an artefact that fail, the first argument is a String like

     {"field_id":65523,"all_links":[{"id":195184,"direction":"forward","type":""}]}
    

    We can't see visual obvious differences between the two artefacts to explain the difference in behavior.

    The issue occurs only with the new artifact link interface.

    Unfortunately, we didn't find a way to reproduce such a case from scratch. Don't hesitate to suggest us things to investigate.

    Trackers
    16.11
    Empty
    • [ ] enhancement
    • [ ] internal improvement
    Empty
    Stage
    Empty
    New
    Empty
    Attachments
    Empty
    References

    Follow-ups

    User avatar

    Thanks for clarification.

    We won't be able to produce any patches on our side. We hope you will be able to patch the code to avoid the insertion of many AL.

    We are currently dealing with remediation on the different concerned projects.

    User avatar

    To be crystal clear on the overall intend: multiple artifact links will never be supported and all cases that might lead to a situation where there are multiple AL fields should be fixed.

    We won't accept patches to workaround this limitation as it will create almost dead code and unneeded complexity on a part of code where we already have way too much cognitive overload.

    User avatar

    We found at least two ways to reproduce the situation:

    • import a tracker's structure generated manually (during a migration from another tool)
    • add a art_link, remove it, add a new one, restore the first one

    Do you plan to fix these scenarios in the context of this issue or do you prefer new separated / dedicated issues?

    Note about the use cases: The teams using two art_link in a single tracker use them to give more semantic on the links and to adapt the visual. For example, they use one art_link for referencing related issues, while the other art_link refers to artifacts representing versions or deliveries. Graphically, these two fields are presented in distinct groups of fields. Just in the case you decide to opt for a solution where multiple art_link are possible.

    User avatar

    I will propose a patch.

    Looking deeper and deeper in the code, I understand that this situation is REALLY unexpected. Thus, there is no way to go.

    Initially, I wished to loop over ALL art_link. But the downstream code really expect a single artifact links collection.

    Then I decided to simply log the suspicious error. But stable/plugins/tracker/include/Tracker/FormElement/Tracker_FormElementFactory.php does not have a logger interface.

    Finally, I don't know what change I can propose. I will focus on the data investigation, in order to evaluate how to remediate our data. I identified 6 trackers concerned over our 8.000 trackers.

    User avatar
    Thomas Gerbet (tgerbet)2025-09-09 14:26

    Hello,

    As an unexpected situation, I would have appreciated a warning when more than one field is found.

    As Joris said we were quite surprised to discover this situation was possible. We did some archeology and we discovered this situation was possible during a few months between 2011 and 2012 until the implementation of git #tuleap/stable/ca0508ff8b82d250e52662c7f53cfd181acb6d46 landed

    I will propose a patch.

    Great news, thanks!

    User avatar

    As an unexpected situation, I would have appreciated a warning when more than one field is found.

    I'm trying to read the history in order to unerstand since when the situation changed, but I'm blocked by the grafted commit 9f557da4882f526f36674a238fec8a0c78f0d928.

    User avatar
    Joris MASSON (jmasson)2025-09-08 16:51

    Thanks for the heads up ! Well, I must say this situation is really unexpected. One of the business rules for the artifact links field is that there should be at most one per tracker. Having two fields of type artifact links is likely going to raise more bugs. I thought this case was forbidden, I wonder how it could have happened.

    User avatar

    I think I found the bug.

    The failing tracker is old and uses TWO fields of type artifact_links.

    The conversion code from JSON to Array is in stable/plugins/tracker/include/Artifact/ChangesetValue/ChangesetValuesContainerBuilder.php in the function getFieldDataForArtifactLinkField. Such function uses getAnArtifactLinkField which searches for the first artifact_links field.

    User avatar
    Joris MASSON (jmasson)2025-09-05 10:53

    From @gbonnefille

    In fact, we are able to reproduce the bug on demand on SOME artifacts. But we are not able to create new artifacts with the same failing behavior.

    When we trigger the issue, the artifact has a link to another artifact. We do not affect this link, we simply change an other field.

    User avatar

    @jmasson We tried to investigate the code. For the moment, the only noticed element is that $submitted_value is typed as array in the convert function, while it is untyped in callers.

    Perhaps adding a type would help to detect the issue sooner.

    User avatar
    • Summary
      -Enable to update an artefact that use an 'Artefact link' field 
      +Unable to update an artefact that use an 'Artefact link' field