diff --git a/public_html/deployment/classes/project.class.php b/public_html/deployment/classes/project.class.php
index 8f5211052f6933ac8fb768cc3d12e7471a991b9a..3f2aa08f8876c1c72fc98a638cde91d1d9d7ded0 100644
--- a/public_html/deployment/classes/project.class.php
+++ b/public_html/deployment/classes/project.class.php
@@ -28,7 +28,7 @@ require_once 'htmlguielements.class.php';
   (...)
   2024-08-28  Axel   php8 only; added variable types; short array syntax
   2024-09-20  Axel   build(): check if checkout of sources failed
-  2024-11-29  Axel   multiple instances for rollout plugins
+  2024-12-05  Axel   multiple instances for rollout plugins; handle errors from callback
   ###################################################################### */
 
 /**
@@ -1583,22 +1583,25 @@ class project extends base
         $sPluginId = (isset($this->_aPrjConfig['deploy']['enabled_rollout_plugin']) && $this->_aPrjConfig['deploy']['enabled_rollout_plugin'])
             ? $this->_aPrjConfig['deploy']['enabled_rollout_plugin']
             : 'default';
-        $sPluginName=$this->_aConfig['plugins']['rollout'][$sPluginId]['plugin'];
+        $sPluginName=$this->_aConfig['plugins']['rollout'][$sPluginId]['plugin'] ?? false;
         unset($this->oRolloutPlugin);
-        try {
-            require_once $this->_getPluginFilename('rollout', $sPluginName);
-            $sPluginClassname = 'rollout_' . $sPluginName;
-            $this->oRolloutPlugin = new $sPluginClassname([
-                'id' => $sPluginId,
-                'lang' => $this->_aConfig['lang'],
-                'phase' => false,
-                'globalcfg' => isset($this->_aConfig['plugins']['rollout'][$sPluginId]) ? $this->_aConfig['plugins']['rollout'][$sPluginId] : [],
-                'projectcfg' => $this->_aPrjConfig,
-            ]);
-            // print_r($this->_oRolloutPlugin->getPluginfos());
-            // print_r($this->_oRolloutPlugin->getName());
-        } catch (Exception $ex) {
-        }
+        if ($sPluginName){
+
+            try {
+                require_once $this->_getPluginFilename('rollout', $sPluginName);
+                $sPluginClassname = 'rollout_' . $sPluginName;
+                $this->oRolloutPlugin = new $sPluginClassname([
+                    'id' => $sPluginId,
+                    'lang' => $this->_aConfig['lang'],
+                    'phase' => false,
+                    'globalcfg' => isset($this->_aConfig['plugins']['rollout'][$sPluginId]) ? $this->_aConfig['plugins']['rollout'][$sPluginId] : [],
+                    'projectcfg' => $this->_aPrjConfig,
+                ]);
+                // print_r($this->_oRolloutPlugin->getPluginfos());
+                // print_r($this->_oRolloutPlugin->getName());
+            } catch (Exception $ex) {
+            }
+        } 
         return true;
     }
 
diff --git a/public_html/deployment/classes/project_gui.class.php b/public_html/deployment/classes/project_gui.class.php
index e43497ffca0e09bb12aaac8b51c60f162a2d615a..4c58299ecb2a30211e3ccf291524f73a22eb7941 100644
--- a/public_html/deployment/classes/project_gui.class.php
+++ b/public_html/deployment/classes/project_gui.class.php
@@ -15,7 +15,7 @@ require_once 'htmlguielements.class.php';
   2013-11-08  Axel <axel.hahn@iml.unibe.ch>
   (...)
   2024-08-26  Axel   php8 only; added variable types; short array syntax
-  2024-11-29  Axel   multiple instances for rollout plugins
+  2024-12-05  Axel   multiple instances for rollout plugins; handle errors from callback
   ###################################################################### */
 
 /**
@@ -851,7 +851,7 @@ class projectgui extends project
             $sMyDivId = 'rollout-' . $sPluginId . '-config';
             $sMyDivClass = 'rolloutconfigdiv';
             $sMyDivClassActive = 'rolloutconfigdiv-' . $sPluginId;
-            $bActive = $sPluginId === $this->oRolloutPlugin->getId();
+            $bActive = isset($this->oRolloutPlugin) && $sPluginId === $this->oRolloutPlugin->getId();
 
             if (file_exists($sPluginFile)) {
                 try {
@@ -1467,14 +1467,18 @@ class projectgui extends project
         // Tab for raw data
         // --------------------------------------------------
 
-        $sRolloutDebug = '<hr>DEBUG:<br>';
-        foreach (array_keys($this->getPhases()) as $sPhase) {
-            if ($this->isActivePhase($sPhase)) {
-                $sRolloutDebug .= '<strong>' . $sPhase . '</strong>'
-                    . '<pre>Config = ' . print_r($this->oRolloutPlugin->getConfig($sPhase, 1), 1) . '</pre>'
-                    . '<pre>Commands = ' . print_r($this->oRolloutPlugin->getDeployCommands($sPhase, 1), 1) . '</pre>'
-                ;
+        $sRolloutDebug = '<hr>DEBUG for rollout:<br>';
+        if (isset($this->oRolloutPlugin)) {            
+            foreach (array_keys($this->getPhases()) as $sPhase) {
+                if ($this->isActivePhase($sPhase)) {
+                    $sRolloutDebug .= '<strong>' . $sPhase . '</strong>'
+                        . '<pre>Config = ' . print_r($this->oRolloutPlugin->getConfig($sPhase, 1), 1) . '</pre>'
+                        . '<pre>Commands = ' . print_r($this->oRolloutPlugin->getDeployCommands($sPhase, 1), 1) . '</pre>'
+                    ;
+                }
             }
+        } else {
+            $sRolloutDebug .= 'INFO: No rollout plugin loaded<br>';
         }
 
         $aForms["setup"]["form"]['input' . $i++] = [
diff --git a/public_html/deployment/classes/rollout_base.class.php b/public_html/deployment/classes/rollout_base.class.php
index f9369b8bb44e453a1e46ba224d5f1841c0fec92f..51c8582dd77ef09c41a5f9a215a9c193e87192fa 100644
--- a/public_html/deployment/classes/rollout_base.class.php
+++ b/public_html/deployment/classes/rollout_base.class.php
@@ -9,7 +9,8 @@ require_once __DIR__ . '/../../vendor/axelhahn/ahcache/cache.class.php';
  * @author axel
  * 
  * Axel <axel.hahn@unibe.ch>
- * 2024-08-29  Axel php8 only; added variable types; short array syntax
+ * 2024-08-29  Axel   php8 only; added variable types; short array syntax
+ * 2024-12-05  Axel   multiple instances for rollout plugins; handle errors from callback
  */
 class rollout_base implements iRolloutplugin
 {
@@ -127,6 +128,20 @@ class rollout_base implements iRolloutplugin
         }
     }
 
+    /**
+     * Add a log messsage
+     * @global object $oLog
+     * 
+     * @param  string $sMessage  messeage text
+     * @param  string $sLevel    warnlevel of the given message
+     * @return bool
+     */
+    private function log(string $sMessage, string $sLevel = "info"): bool
+    {
+        global $oCLog;
+        return $oCLog->add(basename(__FILE__) . " class " . __CLASS__ . " - " ." ".$this->getId()." - ". $sMessage, $sLevel);
+    }
+
     // ---------------------------------------------------------------
     // FORM HELPER
     // ---------------------------------------------------------------
@@ -160,11 +175,16 @@ class rollout_base implements iRolloutplugin
     {
         $oCache = new AhCache('rollout-' . $this->getId(), 'callback-' . $sFunctionname . '-' . $sKey);
         if ($oCache->isExpired()) {
+            $this->log(__FUNCTION__. " calling $sFunctionname to get fresh data");
             $aMydata = call_user_func([$this, $sFunctionname]);
-            // echo "$sFunctionname fresh ".($aMydata ? "OK": "false")." - storing for $iTtl sec<br>";
-            $oCache->write($aMydata, ($aMydata ? $iTtl : $iTtlOnError));
+
+            $bIsError=!$aMydata || isset($aMydata['error']);
+            $iMyTtl=($bIsError ? $iTtlOnError : $iTtl);
+            $this->log(__FUNCTION__. " $sFunctionname was [".($bIsError ? "ERROR": "OK")."] - storing in cache for $iMyTtl sec<br>");
+            // $this->log(__FUNCTION__. ' storing <pre>'.print_r($aMydata,1).'</pre>');
+            $oCache->write($aMydata, $iMyTtl);
         } else {
-            // echo "$sFunctionname from cache ... ".$oCache->iExpired()." sec <br>";
+            $this->log(__FUNCTION__. " SKIP $sFunctionname and use cache ... ".( - $oCache->iExpired())." sec left<br>");
             $aMydata = $oCache->read();
         }
         // echo '<pre>'.print_r($aMydata, 1).'</pre>'; die(__METHOD__);
@@ -188,9 +208,11 @@ class rollout_base implements iRolloutplugin
         $sReturn = '';
         $sKeyPrefix = $this->getId() . '_' . $sKey;
 
+        // $this->log(__FUNCTION__ . " <pre>".print_r($aFormdata, 1).'</pre>');
         $oForm = new formgen();
         foreach ($aFormdata as $elementData) {
             $elementKey = $sKeyPrefix . '_' . $i++;
+            // echo "<hr>$elementKey"; print_r($elementData);
             $sReturn .= $oForm->renderHtmlElement($elementKey, $elementData);
         }
         return $sReturn;
@@ -252,28 +274,39 @@ class rollout_base implements iRolloutplugin
                     (isset($aVarinfos['per_scope']) && $aVarinfos['per_scope'] ? $sKey : ''),
                     (isset($aVarinfos['ttl']) ? $aVarinfos['ttl'] : 60)
                 );
+                // $this->log('<pre>'.print_r($aCallbackData,1).'</pre>');
                 if (!$aCallbackData) {
-                    $aVarinfos['type'] = $aVarinfos['type'] ?? 'text';
+                    // $aVarinfos['type'] = $aVarinfos['type'] ?? 'text';
+                    $aVarinfos['type'] = 'text';
+                    $sMyPlaceholder .= ' ... ERROR: Missing data. Callback function failed.';
+                    $this->log(  'variable field ['.$sVarname.'] ... ERROR: no data callback function '.$aVarinfos['callback'], 'error');
                 } else {
-                    $aEffectiveConfig = $this->getConfig($sPhase);
-                    // echo $sKey.' ... '; print_r($aEffectiveConfig[$sVarname]); echo '<br>';
-
-                    // mark entry as active ... for select and radio
-                    if (isset($aEffectiveConfig[$sVarname]) && isset($aCallbackData[$aEffectiveConfig[$sVarname]])) {
-                        $aCallbackData[$aEffectiveConfig[$sVarname]]['selected'] = 'selected';
-                        $aCallbackData[$aEffectiveConfig[$sVarname]]['checked'] = 'checked';
-                        $aCallbackData[$aEffectiveConfig[$sVarname]]['label'] .= ' &laquo;&laquo;';
-                    } elseif ($aVarinfos['type'] === 'select') {
-                        $aCallbackData = array_merge(['NO_SELECTED_ITEM_YET' => ['value' => '', 'label' => '...']], $aCallbackData);
-                    }
-
-                    // wenn value = defaultvalue, dann value auf '' setzen (damit bei Default vom Scope
-                    // davor ein Leerstring übergeben wird - analog onfocusout im Text Input
-                    if (isset($aCallbackData[$aDefaultValues[$sVarname]])) {
-                        $aCallbackData[$aDefaultValues[$sVarname]]['value'] = '';
-                        $aCallbackData[$aDefaultValues[$sVarname]]['label'] .= ' (*)';
+                    // $this->log(__FUNCTION__ . ' var '.$sVarname.' ... aCallbackData = <pre>'.print_r($aCallbackData,1).'</pre>');
+                    if($aCallbackData['error']){
+                        $aVarinfos['type'] = 'text';
+                        $sMyPlaceholder .= ' ... '.$aCallbackData['error'];    
+                        $this->log(' variable field ['.$sVarname.'] ... error from callback function '.$aVarinfos['callback'].' <pre>'.print_r($aCallbackData,1).'</pre>', 'error');
+                    } else {
+                        $aEffectiveConfig = $this->getConfig($sPhase);
+
+                        // mark entry as active ... for select and radio
+                        if (isset($aEffectiveConfig[$sVarname]) && isset($aCallbackData[$aEffectiveConfig[$sVarname]])) {
+                            $aCallbackData[$aEffectiveConfig[$sVarname]]['selected'] = 'selected';
+                            $aCallbackData[$aEffectiveConfig[$sVarname]]['checked'] = 'checked';
+                            $aCallbackData[$aEffectiveConfig[$sVarname]]['label'] .= ' &laquo;&laquo;';
+                        } elseif ($aVarinfos['type'] === 'select') {
+                            // not needed with bootstrap-select
+                            // $aCallbackData = array_merge(['NO_SELECTED_ITEM_YET' => ['value' => '', 'label' => '...']], $aCallbackData);
+                        }
+
+                        // wenn value = defaultvalue, dann value auf '' setzen (damit bei Default vom Scope
+                        // davor ein Leerstring übergeben wird - analog onfocusout im Text Input
+                        if (isset($aCallbackData[$aDefaultValues[$sVarname]])) {
+                            $aCallbackData[$aDefaultValues[$sVarname]]['value'] = '';
+                            $aCallbackData[$aDefaultValues[$sVarname]]['label'] .= ' (*)';
+                        }
+                        // print_r($aCallbackData[$sVarname]); echo "<br>";
                     }
-                    // print_r($aCallbackData[$sVarname]); echo "<br>";
                 }
                 // echo '<pre>'.$sCallbackfunktion .' = '. print_r($aMydata,1 ).'</pre>';
             }
diff --git a/public_html/deployment/plugins/rollout/awx/rollout_awx.php b/public_html/deployment/plugins/rollout/awx/rollout_awx.php
index 5c791f2e7328cf9f7fdf990db0d3c84b5ee4421b..b97500b9daffada7b412a6c1f1c86263dae7ffa7 100644
--- a/public_html/deployment/plugins/rollout/awx/rollout_awx.php
+++ b/public_html/deployment/plugins/rollout/awx/rollout_awx.php
@@ -9,6 +9,7 @@
  * @author <axel.hahn@iml.unibe.ch>
  * 
  * 2024-09-02  Axel   php8 only; added variable types; short array syntax
+ * 2024-12-05  Axel   multiple instances for rollout plugins; handle errors from callback
  */
 class rollout_awx extends rollout_base
 {
@@ -85,6 +86,7 @@ class rollout_awx extends rollout_base
         curl_setopt($ch, CURLOPT_HEADER, 1);
         curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 
+        // $this->log(__METHOD__ . "Start request $sAwxApiUrl");
         $res = curl_exec($ch);
         if (!$res) {
             $iErrorCode = curl_errno($ch);
@@ -95,7 +97,7 @@ class rollout_awx extends rollout_base
             ];
         }
 
-        $aReturn = ['info' => curl_getinfo($ch), 'error' => curl_error($ch)];
+        $aReturn = ['info' => curl_getinfo($ch)];
         curl_close($ch);
 
         $sHeader = substr($res, 0, $aReturn['info']['header_size']);
@@ -122,16 +124,29 @@ class rollout_awx extends rollout_base
             ]
         );
 
+        if (isset($aResponse['error'])) {
+            $aReturn = [
+                'error' => $aResponse['error'] ,
+                'value' => false,
+                'label' => '!!! Access to awx api for inventories failed !!! ' . $aResponse['error']
+            ];
+            return $aReturn;
+        }        
         if (!isset($aResponse['info']['http_code']) || $aResponse['info']['http_code'] !== 200) {
-            return false;
+            $aReturn = [
+                'error' => 'Non 200 status code '. $aResponse['info']['http_code'] ?? 'none',
+                'value' => false,
+                'label' => '!!! Error from awx api !!! Non 200 status code ' . $aResponse['info']['http_code']
+            ];
+            return $aReturn;
         }
 
         $aData = json_decode($aResponse['body'], 1);
         $aReturn = [];
         if (!$aData || !isset($aData['count'])) {
-            $aReturn[] = [
+            $aReturn = [
                 'value' => false,
-                'label' => '!!! Access to awx api failed !!!'
+                'label' => '!!! No data from awx api !!!'
             ];
             return $aReturn;
         }
@@ -156,8 +171,9 @@ class rollout_awx extends rollout_base
      * [id] => ['value' => [ID], 'label' => [PLAYBOOK] [ID]]
      * @return bool|array
      */
-    public function getAwxJobTemplates()
+    public function getAwxJobTemplates(): array
     {
+        $aReturn = [];
         $aResponse = $this->_httpRequest(
             [
                 'url' => '/job_templates/?order_by=name' . $this->_sAwxApiPaging,
@@ -165,16 +181,29 @@ class rollout_awx extends rollout_base
             ]
         );
 
+        if (isset($aResponse['error'])) {
+            $aReturn = [
+                'error' => $aResponse['error'] ,
+                'value' => false,
+                'label' => '!!! Access to awx api for job templates failed !!! ' . $aResponse['error']
+            ];
+            return $aReturn;
+        }        
         if (!isset($aResponse['info']['http_code']) || $aResponse['info']['http_code'] !== 200) {
-            return false;
+            $aReturn = [
+                'error' => 'Non 200 status code '. $aResponse['info']['http_code'],
+                'value' => false,
+                'label' => '!!! Error from awx api !!! Non 200 status code ' . $aResponse['info']['http_code']
+            ];
+            return $aReturn;
         }
-
+        
         $aData = json_decode($aResponse['body'], 1);
-        $aReturn = [];
         if (!$aData || !isset($aData['count'])) {
-            $aReturn[] = [
+            $aReturn = [
+                'error' => 'no data',
                 'value' => false,
-                'label' => '!!! Access to awx api failed !!!'
+                'label' => '!!! no job templates !!!'
             ];
             return $aReturn;
         }