none
Not convenient Error handling of Folder.Contents RRS feed

  • Question

  • If I try to get context of non-existing folder, it is virtually impossible to gracefully handler the error. "Try" does not do anything around that. Until I use any function that reads the data from table (like Table.RowCount), I cannot catch the error.

    Even passing the result table as a function parameter (which is not so graceful error handling if you do that just for error handling) doesn't force "try" to wake up.

    I would say that the way how "try" works with non existing folder is an error. I pass the wrong directory, the resulting table should not be created at all, so no any stuff around lazy evaluation, streaming semantics, etc.

    Is there any way to gracefully handle the error of Folder.Contents?

    Wednesday, August 14, 2019 2:25 PM

Answers

  • Hi Andrey. Try this:

    = let folder = Folder.Contents("c:\foo"), rowCount = Table.RowCount(folder) in try if rowCount > 0 then folder else null otherwise "An error occurred"

    It looks like Folder.Contents always returns a lazy table, but if the folder doesn't exist, it throws as soon as you start to enumerate. The above forces an enumeration via Table.RowCount before returning the table, which allows "try" to handle the error.

    Ehren

    Tuesday, September 3, 2019 7:45 PM
    Owner

All replies

  • When you use 'try' with any complex value (record, table, list), you will not receive an error. Whenever you use 'try', a record is created. For complex types, the record has two fields - HasError and Value. The HasError field value will be false, and the Value field will contain the complex value type. The complex value type will be evaluated only when accessed (lazily evaluated).

    So to evaluate the complex value immediately with 'try', you access Value field to force evaluation. In the case of folder contents (which returns a table), your code will be something like:

    try Folder.Contents("c:\sharp")[Value]

    Record Example:

    try [x = Int16.From(33000, y = 4] returns HasError as false, and Value as record

    try [x = Int16.From(33000), y = 4][Value] returns HasError as true and an Error field that contains an error record (same as with the Folder.Contents example).

    The same deal applies to lists.

    • Marked as answer by Andrey Minakov Thursday, August 15, 2019 9:13 AM
    • Unmarked as answer by Andrey Minakov Thursday, August 15, 2019 9:32 AM
    Wednesday, August 14, 2019 3:42 PM
  • Hi Colin!

    This is extremely helpful, thanks a lot!

    But I still have a problem with understanding of the syntax. I mean I don't understand why behavior of 

    try Folder.Contents("c:\sharp")[Value]

    is different in comparison with 

    (try Folder.Contents("c:\sharp"))[Value]

    I don't see any clue in the doc for that syntax. I understand what lazy evaluation, but I don't see the point in the syntax why it resolves my issue. I don't mean that it is wrong syntax, but I don't understand it, I would never try to use it due to my understanding of the doc, because I would expect just the syntax error.

    Is it possible to provide a link to something (e.g. some point in the doc), where you picked up this idea (I just expect that I lost something important)? Thanks a lot in advance.

    And - I still think that Folder.Context has an error with error handling. Of course it is philosophy, but if I do not have a folder, no any table should be created, so no any laziness and complex types should be here. IMHO this would be intuitively expected behavior.

    Thursday, August 15, 2019 9:27 AM
  • Oops, I didn't take a look at the error itself.

    And the error is "The column 'Value' of the table wasn't found.", so it seems that is just a wrong usage of "try", because I obviously have this error even if I try to access an existing folder...

    So now I don't see any magic with the syntax, it is just wrong syntax, as I expected. The same is for other examples, provided by Colin.

    Colin, could you clarify?


    Thursday, August 15, 2019 9:35 AM
  • Hi Andrey,

    The situation is a bit more complex than I made it out to be. I omitted some details and provided incorrect syntax.

    The first thing required is to buffer Folder.Contents. This forces evaluation of table, which generates an error if the folder doesn't exist.

    The next step is determined by how you want to handle the error.

    Let's say the our source step is Source = Table.Buffer(Folder.Contents("C:\Sharp"))

    Let's say the next step is Result = try Source. If the folder doesn't exist, try Source returns a record with two fields - [HasError] and [Error]. If the  folder exists, the record contains the fields [HasError] and [Value].

    If you simply want to do something if the error exists, then the Return step would be:

    Return = try Source otherwise … The 'otherwise' clause forces evaluation of the record. If the record has an [Error] field, [HasError] will be true and the otherwise clause is evaluated. If the record has a [Value] field, [HasError] will be false, and [Value] will be evaluated.

    If you want to display the error if the folder doesn't exist, then the return step would be:

    Return = if (try Source)[HasError] then (try Source)[Error][Message] else (try Source)[Value]

    To avoid having to repeat 'try Source' multiple times, just use another step that = try Source

    Thursday, August 15, 2019 7:49 PM
  • Colin, I obviously know how try works.

    My question was about graceful handling of the error. You did not provided the answer at all.

    Let me ask you as a professional, without any emotional component in the question.

    At the first answer you provided wrong syntax. At the second you provided _not graceful_ solution which is obviously worse that I mentioned (you force PQ to evaluate every scalar value of the table, while Table.RowCount at least leave the decision to PQ, which creates hope that it won't).

    So there is not any sign of answer to my question in your comments.

    Could you just say why you place them here? I need the answer to my question, not some interpretation of official documentation which doesn't provide any extra value.

    Please understand, that when you place your messages about nothing, you create the feeling of other busy people that there is some answer to the question, so they do not try to understand what in fact happening here. OR they think that there is too much text here and they will spend too much time in order to understand what is the problem, and they are just passing through while possibly they have a real solution to my problem.

    PLEASE could you be so kind to provide some _useful_ information at least as comments to _my_ questions or not place any comments at all?

    Thank you very much in advance, and sorry for any inconvenience.

    Friday, August 16, 2019 7:56 AM
  • Anthony, thanks for your comment.

    I tried not to be aggressive as possible, but trying not to loose the meaning of my message, which is not pleasant by design. it's a pity if I wasn't successful in softing it as it may be possible, that's my fault. Again, sorry to be not polite enough, and any inconvenience.

    But - while I would be glad if anybody would pick up some ideas from answers which do not address the question, I'd stress that we have to be focused to the topic. If off topic helps to anybody, it doesn't mean that we can speak about anything which may be helpful to somebody, and do it in any quesion. We have to discuss that particular question just because a person, who asked it, needs some concrete help with a particular problem. We cannot make any obstacle for him to get a potential help just because somebody can pick up something useful from discussion about anything but not his problem.

    And discussing some other things create such obstacles for a questioner in the way I described above.

    So, while it may look rude, my comment can help not only me but other developers to get real help and not just usefulness general discussions. If I have to do some dirty but useful job for me and for others, I do it, that's it. We're here to do the job, at the end. Sometimes that means having tuff discussions, in which you have to keep calm and carry on :-).

    Friday, August 16, 2019 10:31 AM
  • Thanks for the kind words Anthony. Just so you know, I am not in the least bit offended. I find Andrey quite amusing actually. We are dealing with the most aggressive personality to ever grace this forum, and pretty soon, will surpass M.Awal as the most prolific questioner. :) My amusement is witnessing the shear torture that he experiences with PQ. He is so unhappy with just about everything, you wonder why he doesn't give up, save everybody's time, and move on to a more compliant application.

    Anyway, it's best to let someone from the development team answer his questions. Even if he is not satisfied by the answers, he shows more respect to those folks.

    'Nuff said.

    Friday, August 16, 2019 12:51 PM
  • Colin, many thanks for you understanding. Have a good weekend :-).
    Friday, August 16, 2019 4:37 PM
  • Hi Andrey. Try this:

    = let folder = Folder.Contents("c:\foo"), rowCount = Table.RowCount(folder) in try if rowCount > 0 then folder else null otherwise "An error occurred"

    It looks like Folder.Contents always returns a lazy table, but if the folder doesn't exist, it throws as soon as you start to enumerate. The above forces an enumeration via Table.RowCount before returning the table, which allows "try" to handle the error.

    Ehren

    Tuesday, September 3, 2019 7:45 PM
    Owner
  • Hi Andrey,

    have you had the chance to try this out?


    Imke Feldmann - MVP Data Platform (PowerBI) - http://www.TheBIccountant.com 

    Please use the 'Mark as answer' link to mark a post that answers your question. If you find a reply helpful, please remember to vote it as helpful - Thanks!

    Sunday, September 29, 2019 7:09 AM
    Moderator