Error when trying to process rows in a Related field list

I have a Service Order Management app that users can place Estimates and then, when approved, convert to an Order. A Work Order object has child references for Products and Materials. When the Estimate is switched to an Order, a Workflow is activated to update Allocated counts in the Inventory table for the associated Products and Materials

I am getting a puzzling error when this Workflow is processed. When I have only a single record in these child references, the updates DO occur as expected in the Inventory table but I still get this error. If there are multiple child records, only the first record is processed and no others. I believe the error is preventing further processing.

What could be causing this error? What am I missing?

Please let me know if you need more information.

Below is the error I am seeing from the log (similar error for each Products and Materials Action sets):

Audit Log Details:

Properties:
{
โ€œAppIdโ€: โ€œea11df8a-9df1-4f29-afea-d6300774751bโ€,
โ€œAppTemplateVersionโ€: โ€œ1.000143โ€,
โ€œRuleNameโ€: โ€œOrder Placedโ€,
โ€œEventTypeโ€: โ€œChangeโ€,
โ€œInvokedByโ€: โ€œUpdateโ€,
โ€œServerโ€: โ€œprodu991100005Tโ€,
โ€œIgnoreSecurityFiltersโ€: false,
โ€œTableNameโ€: โ€œWorkOrdersโ€,
โ€œRuleTableNameโ€: โ€œWorkOrdersโ€,
โ€œOperationUpdateModeโ€: โ€œUPDATES_ONLYโ€,
โ€œEventMatchโ€: โ€œWorkflow event successfully matchedโ€,
โ€œConditionโ€: โ€œ=AND([_THISROW_BEFORE].[Work Type] = โ€œEstimateโ€, [_THISROW_AFTER].[Work Type] = โ€œOrderโ€)โ€,
โ€œMatchesConditionโ€: โ€œTrueโ€,
โ€œActionResultsโ€: โ€œCreated 1 ActionResultsโ€,
โ€œAction Typeโ€: โ€œTakeActionโ€,
โ€œAction Nameโ€: โ€œUpdate Allocation for Materials Usedโ€,
โ€œErrorsโ€: "Error: โ€˜Action on a set of rowsโ€™ โ€˜Update Materials Allocationโ€™ for table 'Materials failed with exception Value cannot be null.\r\nParameter name: source ",
โ€œAppTemplateNameโ€: โ€œServiceInsightBase-526414โ€,
โ€œOperationโ€: โ€œWorkflow actionโ€,
โ€œResultโ€: โ€œFailureโ€
}

0 23 1,455
23 REPLIES 23

2X_6_63882ef0f4ab80ba255f47158c64744c474beea5.png

What type of workflow is this? A data change?

The error is saying that something is blank, or more likely perhaps just not set yet.

Right. The parameter name says โ€œsourceโ€ but I am not sure what that refers to.

The Action sequence is mildly complicated. Iโ€™ll try to explain it in shorthand below:

  1. Action1 - Called from Workflow - Action on set of rows - Rows = โ€œRelated Materialsโ€ - Action = Action 2

  2. Action2 - Called from Action1 - Action on set of rows - Rows = FILTER(Inventory, =Product Code ) - Action = Action 3

  3. Action 3 - Called from Action2 - Data Change - Allocated = SUM(Quantity in Material Rows =Product Code)

It is in Action 2 where the error is being reported - even after correct processing of the single or first row. I would assume that the โ€œsourceโ€ here is the โ€œRelated Materialsโ€ rows and it is definitely not null. Not sure why it thinks so.

Can I not chain Actions in this manner? Am I missing a more simplified way to achieve the same thing?

By the way this is not a deployed app, is there any testing limitations I might be hitting?

Thereโ€™s something a miss here.

It seems like youโ€™ve got a trigger, the workflow, that initiates action 1โ€ฆ

that initiates action 2โ€ฆ

that finally does what you want.

Why the middle ground with action 2??

For each new Material record added, I am recalculating the Total Allocated amount and applying that to the Inventory record instead of trying to make increments/decrements as records are added or changed.

To do that, I first need to translate the Material record to the associated Inventory row based on Product Code. Then I can update that rows Quantity Allocated value.

I am starting with a Work Order:

Action1 - Translates processing to the List of Materials records on the Work Order - โ€œRelated Materialsโ€
Action2 - Finds the associated Inventory record by product code (always expect 1 row here)
Action3 - Updates the Inventory row based on SUM calculation.

I donโ€™t think I can skip Action2 because I need that reference to the Inventory record in order to update it in Action 3.

Maybe I can combine Action1 and Action2? I really just need a reference to the list of Inventory rows that need updated - in this case based on the Materials list on the Work Order.

@MultiTech_Visions Ok, I did combine Action1 and Action2 to go directly to a list of Inventory records from the Work Order. I used a Reference Rows function like this:

FILTER(โ€œInventoryโ€, IN([Product Code], [Related Products][Product Code]))

This gets me the list of Inventory rows that I want to update the Quantity Allocated column for.

I am no longer getting the error message in the log.

Thank you for getting me thinking for an alternative approach!!!

Iโ€™d still like to know the reason for the error. I think logically the structure was ok. Can I not have nested Actions on row sets?

I"m not sure exactly either, but Iโ€™m glad you got it working! (^_^)

FYI, as I test, It appears that the syntax " [Related Products][Product Code]" doesnโ€™t work as I had thought. I thought I would get a list of Product Codes for just the records in โ€œRelated Productsโ€. However, it appears I get a list of Product Codes for the entire table Products. Is this expected?

Negative, this is a bug.

@Aleksi @praveen

Ok then! Iโ€™ll open this as a bug and create a little sample app to simplify the issue I am seeing. For now I have switched to using a SELECT() statement to work around the problem.

Donโ€™t you want [Related Products].[Product Code] ?

The dot is used to dereference a value from a single row. In this case I have a list of rows, like in an actual table.

This syntax ( [Related Products][Product Code] ) is called a โ€œReverse Referenceโ€ (itโ€™s extremely helpful when youโ€™ve got a large amount of data) and basically what it does is the same as a SELECT() to pull a list of values, but only running on the list of related records.

This has the benefit of reducing the dataset needing for the system to run over; imagine if you had 100,000 rows in a sheet, you wouldnโ€™t want to run a SELECT() over that many rows - so you can cut it down by the reverse reference.

But there is a persistent bug where instead of restricting the query to the related rows, they system runs the query over the whole table (giving you everything instead of just the filtered data).

Bahbus
New Member

So Related Products is not just a List of References?

Bahbus
New Member

Hmm that may have been why I had similar difficulties that I solved in other ways. I mean I know that reverse references existed, I just kept assuming they didnโ€™t do things I wanted to. I thought this was just related to the way IN works. I think the FILTER and IN functions could still work, but I would need to have a much better understanding of the data to make it work. I think I might be doing something similar where a reverse ref would have been nice.

But, hey, as long as you got it working one way or the other.

I must confess, I havenโ€™t kept up with the technical aspects of the processing to truly understand whatโ€™s going on behind the scenes within both AppSheet servers and on the device the app is running.

I hadnโ€™t really thought of [Related Products] as a list of references but I guess that is truly the mechanism being used as opposed as a reference to a list of rows.

Yeah, thatโ€™s why I assume its bugged and not working correctly. In my head, regardless of right or wrong, [Related Products][Product Code] says "give me all the product codes of every related product in the entire Inventory table. Which is why it made sense to me that it wasnโ€™t working since you basically created an IN statement that (basically) always resolves to true. My thinking was the dereference would hopefully force it check for just the list of product codes related to the current entry very much akin to using a [_THISROW] dereference. Maybe I was thinking of something like [_THISROW].[Related Products][Product Code].

I think part of the problem is understanding how some functions works under the hood. For example, we know the FILTER function is just a compact version of SELECT and ultimately that is all AppSheet is doing is translating FILTER to SELECT. And there is an example or two in the docs that tell you that. But we donโ€™t know exactly how AppSheet parses the data to create the actual SELECT it uses. We also donโ€™t have more information on examples on how it does not work. Hence, it ended being easier to write a SELECT yourself that worked.

There are quite a few commands and instances where much, much, much more information would be useful that I ultimately have to come here for.

[Related Things][SomeColumn] is essentially:

SELECT(
  Thing[SomeColumn],
  IN([RowKey], [_THISROW].[Related Things])
)

FILTER(table-name, condition) is equivalent to SELECT(table-name[key-column], condition, false). Itโ€™s essntially a macro. Thereโ€™s no magic in it.

Similarly, LOOKUP(search-expression, table-name, search-column-name, result-column-name) is essentally a macro for ANY(SELECT(table-name[result-column-name], (search-expression = [search-column-name]), false)).

Can you elaborate?

There were some examples somewhere of common problems people have with SELECT and how it doesnโ€™t work.

I actually decided to start writing up a seperate post altogether describing the problem Iโ€™m having. Iโ€™ll @ you in the post.

Wouldnโ€™t โ€œ[Related Products][Product Code]โ€ be the same as โ€œ[_THISROW].[Related Products][Product Code]โ€ in the context in which it was used above? It is my understanding that you really only need โ€œ[_THISROW]โ€ to resolve ambiguity.

With regards to knowing how things work under the hood, I would agree. And it would be great if there was a more comprehensive knowledge base we could go to get answers.

On the other hand, creating such a knowledge base is time consuming which translates to expensive. And it is only as good as the last update! So its kinda a catch-22.

On the bright side, its always good to chat with like minded people to figure our โ€œproblemsโ€ out together!!

I guess it depends. I donโ€™t know if any of my suggestions would end up computing correctly. I was thinking of it, because I saw this in the expression builder:
2X_a_a8d3a2436aa225d0f9d577610ef9f5dfb65ba3e7.png

Ref lists are weird beasts. I am having my own hard time with a ref enumlist. The data all works perfectly. Itโ€™s the dashboard interactive part it doesnโ€™t like.

EnumList of type Ref is really not well supported. What are you trying to do?

Inside SELECT()(-ish) functions, that have their own frames of reference, [_THISROW] gives you direct access to the row from which the SELECT() was invoked. I recommend always using [_THISROW] if you intend to reference the enclosing row, else you run the risk that an identically-named column will be added to a scanned table and produce ambiguity and confusion unexpectedly.

Outside a SELECT()(-ish) function, [_THISROW] is equivalent to dereferencing the current rowโ€™s key column. So if your key column is RowKey, [_THISROW] and [RowKey] are equivalent.

SELECT()(-ish) functions are: FILTER(), LOOKUP(), MAXROW(), MINROW(), and SELECT().

Understood and a very good practice (which I utilize myself). BUTโ€ฆI donโ€™t believe its required. I remember when I first started creating complex conditions. I found all the _THISROW references were making it hard to read the condition. I started naming columns uniquely to avoid this.

For example, in Product table I would have had โ€œProduct Codeโ€ while in Purchase Order table I might have had โ€œPO Prod Codeโ€. This is considered by some a good db naming practice as you can easily identify the source table from the name - especially in error msgs.

Anyway, my point is that you will not need _THISROW if columns are named in this manner. AppSheet can resolve without conflict.

And by the way, I have relaxed on such naming conventions. Getting lazy I guess!

Top Labels in this Space