Object reference not set to an instance of an object. (Deadline.Events.DeadlineEventPluginException)

I am trying to use an EventPlugin called ‘deadlineslack’ from here: DeadlineSlack/DeadlineSlack/DeadlineSlack.py at master · Colorbleed/DeadlineSlack · GitHub

I fixed up imports and the super().__init__() call

I am seeing this error in the console and can’t figure it out

2025-03-23 16:09:07:  Event plugin 'DeadlineSlack' could not be loaded from the repository because: An error occurred in function "GetDeadlineEventListener" the event plugin script file "D:\DeadlineRepository10\custom\events\DeadlineSlack\DeadlineSlack.py": Object reference not set to an instance of an object. (Deadline.Events.DeadlineEventPluginException)

here the script cleaned by Claude 3.7

from Deadline.Events import DeadlineEventListener
from Deadline.Scripting import RepositoryUtils

import requests
import json
from datetime import datetime

def GetDeadlineEventListener():
    return DeadlineSlackEvent()

def CleanupDeadlineEventListener(deadlinePlugin):
    deadlinePlugin.Cleanup()

class DeadlineSlackEvent(DeadlineEventListener):
    def __init__(self):
        super().__init__()
        
        self.LogInfo("DeadlineSlack plugin initializing...")
        
        # Initialize all callbacks directly like in the default implementation
        self.OnJobFinishedCallback += self.OnJobFinished
        self.OnJobDeletedCallback += self.OnJobDeleted
        self.OnJobFailedCallback += self.OnJobFailed
        self.OnJobPendedCallback += self.OnJobPended
        self.OnJobReleasedCallback += self.OnJobReleased
        self.OnJobRequeuedCallback += self.OnJobRequeued
        self.OnJobResumedCallback += self.OnJobResumed
        self.OnJobPurgedCallback += self.OnJobPurged
        self.OnJobStartedCallback += self.OnJobStarted
        self.OnJobSubmittedCallback += self.OnJobSubmitted
        self.OnJobSuspendedCallback += self.OnJobSuspended
        self.OnJobErrorCallback += self.OnJobError
        self.OnSlaveIdleCallback += self.OnSlaveIdle
        self.OnSlaveStalledCallback += self.OnSlaveStalled
        self.OnSlaveStartedCallback += self.OnSlaveStarted
        self.OnSlaveStoppedCallback += self.OnSlaveStopped
        self.OnSlaveRenderingCallback += self.OnSlaveRendering
        self.OnSlaveStartingJobCallback += self.OnSlaveStartingJob
        
        self.LogInfo("DeadlineSlack plugin initialized")

    def Cleanup(self):
        # Explicitly clean up all callbacks
        del self.OnJobFinishedCallback
        del self.OnJobDeletedCallback
        del self.OnJobFailedCallback
        del self.OnJobPendedCallback
        del self.OnJobReleasedCallback
        del self.OnJobRequeuedCallback
        del self.OnJobResumedCallback
        del self.OnJobPurgedCallback
        del self.OnJobStartedCallback
        del self.OnJobSubmittedCallback
        del self.OnJobSuspendedCallback
        del self.OnJobErrorCallback
        del self.OnSlaveIdleCallback
        del self.OnSlaveStalledCallback
        del self.OnSlaveStartedCallback
        del self.OnSlaveStoppedCallback
        del self.OnSlaveRenderingCallback
        del self.OnSlaveStartingJobCallback
        
        self.LogInfo("DeadlineSlack plugin cleaned up")

    # Event handlers
    def OnJobFinished(self, job):
        self.on_job("OnJobFinished", job)

    def OnJobDeleted(self, job):
        self.on_job("OnJobDeleted", job)

    def OnJobFailed(self, job):
        self.on_job("OnJobFailed", job)

    def OnJobPended(self, job):
        self.on_job("OnJobPended", job)

    def OnJobReleased(self, job):
        self.on_job("OnJobReleased", job)

    def OnJobRequeued(self, job):
        self.on_job("OnJobRequeued", job)

    def OnJobResumed(self, job):
        self.on_job("OnJobResumed", job)

    def OnJobPurged(self, job):
        self.on_job("OnJobPurged", job)

    def OnJobStarted(self, job):
        self.on_job("OnJobStarted", job)

    def OnJobSubmitted(self, job):
        self.on_job("OnJobSubmitted", job)

    def OnJobSuspended(self, job):
        self.on_job("OnJobSuspended", job)

    def OnJobError(self, job, task, report):
        self.on_job_error("OnJobError", job, task, report)

    def OnSlaveIdle(self, slave):
        self.on_slave("OnSlaveIdle", slave)

    def OnSlaveStalled(self, slave):
        self.on_slave("OnSlaveStalled", slave)

    def OnSlaveStarted(self, slave):
        self.on_slave("OnSlaveStarted", slave)

    def OnSlaveStopped(self, slave):
        self.on_slave("OnSlaveStopped", slave)

    def OnSlaveRendering(self, slave, job):
        self.on_slave_job("OnSlaveRendering", slave, job)

    def OnSlaveStartingJob(self, slave, job):
        self.on_slave_job("OnSlaveStartingJob", slave, job)

    # Helper methods
    def _get_message(self, key):
        config = RepositoryUtils.GetEventPluginConfig("DeadlineSlack")
        config_key = "Slack{0}Message".format(key)
        message = config.GetConfigEntryWithDefault(config_key, "")
        
        if message:
            message = message.replace(";", "\n")
        
        return message

    def on_job(self, key, job):
        self.LogInfo(f"on_job callback triggered for {key} with job ID: {job.JobId}")
        message = self._get_message(key)
        if message:
            try:
                formatted_message = message.format(job=job)
                self._post(formatted_message)
            except Exception as e:
                self.LogWarning(f"Error formatting message for {key}: {str(e)}")

    def on_job_error(self, key, job, task, report):
        message = self._get_message(key)
        if message:
            self._post(message.format(job=job, task=task, report=report))

    def on_slave(self, key, slave):
        message = self._get_message(key)
        if message:
            self._post(message.format(slave=slave))

    def on_slave_job(self, key, slave, job):
        message = self._get_message(key)
        if message:
            self._post(message.format(slave=slave, job=job))

    def send_slack_message(self, message):
        try:
            config = RepositoryUtils.GetEventPluginConfig("DeadlineSlack")
            
            token = config.GetConfigEntryWithDefault("SlackAPIKey", None)
            if not token:
                self.LogWarning("No Slack API key configured in Deadline")
                return {"ok": False, "error": "No Slack API key configured"}
                
            channel = config.GetConfigEntryWithDefault("SlackChannel", None)
            if not channel:
                self.LogWarning("No Slack channel configured in Deadline")
                return {"ok": False, "error": "No Slack channel configured"}
                
            as_user = config.GetBooleanConfigEntryWithDefault("SlackAsUser", True)
            
            url = "https://slack.com/api/chat.postMessage"
            headers = {
                "Authorization": f"Bearer {token}",
                "Content-Type": "application/json; charset=utf-8",
            }
            data = {
                "channel": channel, 
                "text": message,
                "as_user": as_user
            }
            
            response = requests.post(url, headers=headers, json=data)
            response_data = response.json()
            
            if not response_data.get("ok", False):
                self.LogWarning(f"Failed to send Slack message: {response_data.get('error', 'Unknown error')}")
            
            return response_data
        except Exception as e:
            self.LogWarning(f"Exception when sending Slack message: {str(e)}")
            return {"ok": False, "error": str(e)}

    def _post(self, message):
        try:
            self.send_slack_message(message)
        except Exception as e:
            self.LogWarning(f"Exception in _post method: {str(e)}")

At first sight it looks ok. But I believe this error means there is still an issue with loading/importing the plugin.
By the way event plugins now run in their own process (“sandbox”), so you should check the worker’s log at the moment it attempts to import it.

1 Like

thank you @mois.moshev I’ll check