8 Replies Latest reply on Dec 27, 2012 2:55 PM by johnrellis

    Internal error when calling 'catalog:createKeyword'

    Thorsten A K Level 1

      Hello everyone,

       

      I am in the decision making process of migrating to Lightroom. One important aspect is, that I am able to somehow import my existing keywords for my photos (currently within ACDSee). I succeeded with the easy part already: converting the categories into a TAB-based text format and importing this as keywords in Lightroom.

       

      Now I want to associate the images to the already imported keywords. The following thread brought me up to speed very quickly: http://adobe.hosted.jivesoftware.com/thread/1033982?tstart=0

       

      But now I am somehow struck. I can get the root keyword directly, and I am also able to get its children. Alas, whenever I am calling createKeyword with a parent I got the following error message:

       

      "An internal error has occurred: ?:0: attempt to index a nil value"

       

      Any ideas what might be the cause?

       

      Here is the script, encapsulating the problem, if this helps:

       

      local LrDialogs = import 'LrDialogs'
      local LrApplication = import 'LrApplication'
      local catalog = LrApplication.activeCatalog()
      
      
      MyMenuItem = {}
        
      function MyMenuItem.runProcess()
          catalog:withWriteAccessDo("setKeywords", MyMenuItem.setKeywords)
      end 
      
      function MyMenuItem.setKeywords()             
                local targetPhotos = catalog:getTargetPhotos() 
                if targetPhotos ~= nil and #targetPhotos > 0 then 
                          -- LrDialogs.message(#targetPhotos)
                else
                          LrDialogs.message( "No target photos." )
                          return
                end 
      
      
                -- ( keywordName, synonyms, includeOnExport, parent, returnExisting )
                local myRootKeyword = catalog:createKeyword( 'People', nil, true, nil, true ) 
                if myRootKeyword ~= nil then
                          LrDialogs.message(myRootKeyword:getName())
                else
                          LrDialogs.message( "Keyword has not been returned." )
                          return
                end
        
                local childs = myRootKeyword:getChildren()
                for i,child in ipairs( childs ) do
                          LrDialogs.message(child:getName())
                end
                -- Shows Friends, Others, ...
        
                LrDialogs.message( "createKeyword is about to be called" ) 
        
                -- Crashes after this line "An internal error has occurred: ?:0: attempt to index a nil value"
                local mySecKeyword = catalog:createKeyword( 'Friends', nil, true, myRootKeyword, true )
                if mySecKeyword ~= nil then
                          LrDialogs.message(mySecKeyword:getName())
                else
                          LrDialogs.message( "Keyword has not been returned." )
                          return
                end
      end
      
      
      import 'LrTasks'.startAsyncTask( MyMenuItem.runProcess )
      
      
      
      
      

        

      Thanks for any hints in advance.

       

      Kind Regards,

      Thorsten

        • 1. Re: Internal error when calling 'catalog:createKeyword'
          johnrellis Most Valuable Participant

          SDK Lua errors are rarely very cluefull, but this one gives a reasonable hint:

           

          "An internal error has occurred: ?:0: attempt to index a nil value"

           

          That means that some code expects an array and is trying to index it, but in fact the array value is nil. In your suspect line:

           

          local mySecKeyword = catalog:createKeyword( 'Friends', nil, true, myRootKeyword, true )

           

          the second argument to createKeyword() is supposed to be an array of synonyms:

           

          catalog:createKeyword( keywordName, synonyms, includeOnExport, parent, returnExisting )
          2. synonyms

          (table) The names of synonyms.

           

          But you're passing nil, which is not the same thing as an empty array {}.

          • 2. Re: Internal error when calling 'catalog:createKeyword'
            areohbee Level 5

            Seems like this method should be robustened a smidge so nil is treated as none, but the behavior is consistent with the documentation - it does not claim the synonyms array is optional.

            • 3. Re: Internal error when calling 'catalog:createKeyword'
              Thorsten A K Level 1

              Thank you for your reply. Given that I am new to Lua and Lightroom SDK, I already tried some variations of calling. So regretably there is not difference when passing an empty array or nil.

               

              I also noticed now, that the first call of createKeyword only works, when the keyword already exists. Otherwise the same error message is returned.

               

              So this line works, when there is a root keyword named "People".

               

              local myRootKeyword = catalog:createKeyword( 'People', {}, true, nil, true )

               

              I even tried the plugin again, with a new empty catalog without any other plugins with the same results.

               

              Could it be any shortcomings with respect to security? E.g. related to "withWriteAccessDo".

              Are there any further settings I could dig into?

               

              Thanks again,

              Thorsten

              • 4. Re: Internal error when calling 'catalog:createKeyword'
                johnrellis Most Valuable Participant

                Ah, the problem is that you're trying to call myRootKeyword:getName() before exiting the catalog:withWriteAccessDo().  The doc for catalog:createKeyword() says:

                 

                Must be called from within one of the with__WriteAccessDo gates. The new keyword is not available for access until that function returns.

                 

                If instead, you restructure your code like this:

                local myRootKeyword 
                catalog:withWriteAccessDo("setKeywords", function ()  
                    myRootKeyword = catalog:createKeyword( 'People', {}, true, nil, true )
                    end)
                

                It works just fine.

                 

                By the way, your comment "Crashes after this line" was incorrect.  I suggest you use the Debugging Toolkit, which will make it much quicker to identify your bugs. It will take some time to hook it up the first time, but it will pay off pretty quickly.

                • 5. Re: Internal error when calling 'catalog:createKeyword'
                  Thorsten A K Level 1

                  John, thank you very much. That really was the issue.

                   

                  I didn't consider that, since photo:addKeyword() worked :-) Now everything works and I can get started.

                   

                  Regards,

                  Thorsten

                  • 6. Re: Internal error when calling 'catalog:createKeyword'
                    areohbee Level 5

                    Yep. - I shoulda thoughta that - happens a lot. So much that I made a special multi-phase catalog updater:

                     

                    cat:update( 10, "Create Keyword", function( context, phase ) -- 10 is timeout

                         if phase == 1 then

                              -- create root keyword

                              return false -- continue to next phase, in a new with-do block.

                         elseif phase == 2 then

                              -- create child keyword.

                              return true -- done

                         else

                              error( "plugin is broken" )

                         end

                    end )

                     

                    I wish I had done that a long time ago - very convenient.

                     

                    Available as part of the Elare Plugin Framework.

                     

                    Rob

                    • 7. Re: Internal error when calling 'catalog:createKeyword'
                      Thorsten A K Level 1

                      Thanks again for your recommendation to use the Debugging Toolkit. This really saved my day several times so far.

                       

                      One question: do you recommend to let the debug glue code as well as the libraries included within a distribution?

                      I've got the CSV keyword importer available at https://github.com/tkampp/lr-keyword-importer

                       

                      Thanks,

                      Thorsten

                      • 8. Re: Internal error when calling 'catalog:createKeyword'
                        johnrellis Most Valuable Participant

                        I recommend including the toolkit in your distributed plugin, for a couple of reasons:

                         

                        - The "require 'strict'" will still catch (heaven forbid) any "undeclared" (probably misspelled) variables that your testing missed.

                         

                        - The calls to Debug.showErrors() will cause the standard LR error dialog to be displayed when a task encountered an error, rather than for the error to be silently ignored (the default). 

                         

                        Note that by default, the debugger is disabled when the plugin is run from a folder ending in ".lrplugin", so you don't need to worry about the debugger window appearing in front of users.

                         

                        The size of the toolkit (Debug.lua, Require.lua, strict.lua) is small, about 2000 lines.  There's no need to distribute DebugScript.lua.