title: why is this Python code failing in the stomp library - missing message argument?
body: <p>The company I work for has a Python test script which posts a message to a AMQ (input) topic using Python 3.x. The test script is configured to consume resulting messages from an output topic.
  I have written a Python script which receives the AMQ message on a topic, does it's processing and posts another message onto a different (output) topic.</p>
  <p>My issue is this, when running the test script in Ubuntu v20 I receive the following error message:</p>
  <pre><code>Traceback (most recent call last):
    File &quot;/usr/lib/python3.6/threading.py&quot;, line 916, in _bootstrap_inner
      self.run()
    File &quot;/usr/lib/python3.6/threading.py&quot;, line 864, in run
      self._target(*self._args, **self._kwargs)
    File &quot;/home/robot/.local/lib/python3.6/site-packages/stomp/transport.py&quot;, line 348, in __receiver_loop
      self.process_frame(f, frame)
    File &quot;/home/robot/.local/lib/python3.6/site-packages/stomp/transport.py&quot;, line 193, in process_frame
      self.notify(frame_type, f)
    File &quot;/home/robot/.local/lib/python3.6/site-packages/stomp/transport.py&quot;, line 248, in notify
      notify_func(frame)
  TypeError: on_message() missing 1 required positional argument: 'message'
  </code></pre>
  <p>Here is the code which receives messages on the input topic, processes them and places messages on the output topic:</p>
  <pre><code>#!/usr/bin/env python3
  
  import time
  import os
  import threading
  import logging
  import signal
  import stomp
  import config_with_yaml as config
  import sys
  from src import factory
  
  console = logging.StreamHandler()
  formatter = logging.Formatter('[%(asctime)s] %(name)-12s %(levelname)-8s %(message)s')
  console.setFormatter(formatter)
  logging.getLogger().addHandler(console)
  logging.getLogger().setLevel(logging.INFO)
  LOGGER = logging.getLogger('my-client')
  
  
  class MyConfig:
      def __init__(self):
  
      # boiler plate config
   
  
  
  
  config = MyConfig()
  
  
  def connect_and_subscribe(conn):
      conn.connect(config.amq_username, config.amq_password, wait=True, headers={'client-id': config.client_id})
      conn.subscribe(destination=config.in_topic, id=config.subscription_id, ack='auto',
                     headers={'activemq.subscriptionName': config.subscription_name, 'activemq.prefetchSize': 1})
  
  
  class MyListener(stomp.ConnectionListener):
      def __init__(self, conn):
          self.conn = conn
  
      def on_error(self, headers, message):
          logging.error('received an error &quot;%s&quot;' % message)
  
      def on_message(self, headers, message):
          # MESSAGE PROCESSING START
          logging.debug('message recieved')
          logging.debug('headers: &quot;%s&quot;' % str(headers))
          logging.debug('message: &quot;%s&quot;' % message)
          logging.debug('processing &quot;%s&quot;  message' % config.name)
  
          df = factory.dataflow_factory(config.location, config.name.lower(), message)
          body = df.process()
          logging.debug('message processed: &quot;%s&quot;' % str(body))
          # # MESSAGE PROCESSING END
  
          # # Send response message
          self.conn.send(body=body, destination=config.out_topic)
          logging.debug('response sent')
  
      def on_disconnected(self):
          logging.debug('disconnected, reconnecting...')
          with self.conn.need_reconnect:
              self.conn.need_reconnect.notify()
  
  
  class ConnectThread(threading.Thread):
      def __init__(self, conn):
          threading.Thread.__init__(self)
          self.daemon = True
          self.conn = conn
  
      def run(self):
          while True:
              try:
                  if not self.conn.is_connected():
                      logging.info(&quot;client ready to connect to AMQ&quot;)
                      connect_and_subscribe(self.conn)
                      with self.conn.need_reconnect:
                          self.conn.need_reconnect.wait()
              except Exception as ex:
                  template = &quot;An exception of type {0} occurred. Arguments:\n{1!r}&quot;
                  message = template.format(type(ex).__name__, ex.args)
                  logging.warning(message)
                  time.sleep(5)
  
  
  class ActiveDaemon(object):
      def __init__(self):
          self.stop = False
          signal.signal(signal.SIGINT, self.go_down)
  
          self.conn = stomp.Connection(host_and_ports=config.hosts, keepalive=True, reconnect_attempts_max=1)
          self.conn.set_ssl(for_hosts=config.hosts, key_file=config.amq_key_file_location,
                            cert_file=config.amq_cert_file_location)
          self.conn.need_reconnect = threading.Condition()
          self.conn.set_listener('', MyListener(self.conn))
  
      def run(self):
          connection_thread = ConnectThread(self.conn)
          connection_thread.start()
  
          logging.info(&quot;client daemon running&quot;)
  
          while not self.stop:
              time.sleep(2)
  
          self.conn.disconnect()
  
      def go_down(self, signum, frame):
          logging.info(&quot;Exit command received&quot;)
          self.stop = True
  
  
  if __name__ == &quot;__main__&quot;:
      logging.info(&quot;client starting...&quot;)
      daemon = ActiveDaemon()
      logging.info(&quot;client daemon created&quot;)
      daemon.run()
  
  
  </code></pre>
  <p>Here is the consumer code from the script.</p>
  <pre><code>class Consumer(ActiveMQConnection):
      def __init__(self, host: str, port: str, cert_key_location: str, cert_file_location: str, username: str,
                   password: str, subscription_topic: str):
          self.conn = None
          self.subscription_topic = subscription_topic
          self.class_name = self.MessageListener
          self.username = username
          self.password = password
          ActiveMQConnection.__init__(self, host=host, port=port, cert_key_location=cert_key_location,
                                      cert_file_location=cert_file_location, is_consumer=True)
  
      def connect_and_subscribe(self, expected_msg_count: int, time_limit_seconds: int) -&gt; int:
          global EXPECTED_MSG_COUNT
          EXPECTED_MSG_COUNT = expected_msg_count
          while EXPECTED_MSG_COUNT != ACTUAL_MSG_COUNT:
              self.conn = self.get_connection()
  
          return ACTUAL_MSG_COUNT
  
      class MessageListener:
          def __init__(self, conn: object):
              self.conn = conn
  
          def on_error(self, headers, message):
              logging.error(&quot;Received an error with message: &quot; + message)
  
          def on_message(self, headers, message):
              global ACTUAL_MSG_COUNT
              logging.debug(&quot;Message Received: &quot; + message)
              ACTUAL_MSG_COUNT += 1
  </code></pre>
  <p>Now, here's the strange thing. A colleague can run this code without error in Ubuntu (not sure of the version), same Python version 3.6 (also occurs with 3.8) with the same AMQ instance (dockerised) and the same code to process the messages (also dockerised).</p>
  <p>I've tried adding output to the stomp library, to no avail.</p>
  <p>I did note though that I was observing two indentical log messages from within stomp's transport.py script in the listener's loop:</p>
  <pre><code>INFO:stomp.py:Received frame: 'CONNECTED', len(body)=0
  INFO:stomp.py:frame type = connected
  INFO:stomp.py:frame type = connected
  INFO:stomp.py:Sending frame: 'SUBSCRIBE'
  INFO:stomp.py:notify_func = &lt;bound method HeartbeatListener.on_connected of &lt;stomp.connect.StompConnection11 object at 0x7fb7033b2160&gt;&gt;
  INFO:stomp.py:frame type = before_message
  INFO:stomp.py:frame type = before_message
  INFO:stomp.py:notify_func = &lt;bound method ConnectionListener.on_before_message of &lt;stomp.connect.StompConnection11 object at 0x7fb7033b2160&gt;&gt;
  INFO:stomp.py:Received frame: 'MESSAGE', len(body)=21
  INFO:stomp.py:frame type = message
  INFO:stomp.py:notify_func = &lt;bound method Consumer.MessageListener.on_message of &lt;__main__.Consumer.MessageListener object at 0x7fb702c9bf60&gt;&gt;
  INFO:stomp.py:Receiver loop ended
  INFO:stomp.py:frame type = receiver_loop_completed
  INFO:stomp.py:frame type = receiver_loop_completed
  INFO:stomp.py:notify_func = &lt;bound method ConnectionListener.on_receiver_loop_completed of &lt;stomp.connect.StompConnection11 object at 0x7fb7033b2160&gt;&gt;
  INFO:stomp.py:frame type = disconnected
  INFO:stomp.py:frame type = disconnected
  Exception in thread Thread-2:
  
  
  </code></pre>
  <p>Can't be sure if that should be happening or not.</p>