Skip to content

Commit 1c69b6b

Browse files
jared mauchjared mauch
authored andcommitted
Fix pipeline attribute handling in IncomingRunner._get_pipeline
Fixed a bug where MailList.__getattr__ returning 0 for missing pipeline attributes caused 'pipeline is not a list: 0 (type: int)' errors in the error log. The code now properly validates pipeline attributes and correctly prioritizes pipeline sources (msgdata > mlist.pipeline > GLOBAL_PIPELINE). Also improved error logging to indicate the source of invalid pipeline values for easier debugging.
1 parent e092585 commit 1c69b6b

1 file changed

Lines changed: 26 additions & 5 deletions

File tree

Mailman/Queue/IncomingRunner.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -139,17 +139,38 @@ def _dispose(self, mlist, msg, msgdata):
139139
def _get_pipeline(self, mlist, msg, msgdata):
140140
# We must return a copy of the list, otherwise, the first message that
141141
# flows through the pipeline will empty it out!
142+
# Priority order (as per comment in _dispose):
143+
# 1. msgdata['pipeline'] (for requeued messages with retry pipeline)
144+
# 2. mlist.pipeline (list-specific pipeline override)
145+
# 3. mm_cfg.GLOBAL_PIPELINE (default fallback)
142146
pipeline = msgdata.get('pipeline')
143147
if pipeline is None:
144-
pipeline = getattr(mlist, 'pipeline', None)
145-
else:
146-
# Use the already-imported mm_cfg directly
148+
# Check if mlist actually has a pipeline attribute (not just __getattr__ default)
149+
# MailList.__getattr__ returns 0 for missing attributes, so we need to check
150+
# if it's actually a list before using it
151+
if hasattr(mlist, '__dict__') and 'pipeline' in mlist.__dict__:
152+
pipeline = mlist.pipeline
153+
else:
154+
# Try getattr, but validate the result since __getattr__ might return 0
155+
pipeline = getattr(mlist, 'pipeline', None)
156+
# If __getattr__ returned 0 (or other non-list), treat as missing
157+
if not isinstance(pipeline, list):
158+
pipeline = None
159+
# If pipeline is still None, use the global pipeline
160+
if pipeline is None:
147161
pipeline = mm_cfg.GLOBAL_PIPELINE
148162

149163
# Ensure pipeline is a list that can be sliced
150164
if not isinstance(pipeline, list):
151-
syslog('error', 'pipeline is not a list: %s (type: %s)',
152-
pipeline, type(pipeline).__name__)
165+
# Log where the invalid pipeline came from for debugging
166+
if 'pipeline' in msgdata:
167+
source = 'msgdata'
168+
elif hasattr(mlist, '__dict__') and 'pipeline' in mlist.__dict__:
169+
source = 'mlist.pipeline (list: %s)' % mlist.internal_name()
170+
else:
171+
source = 'unknown'
172+
syslog('error', 'pipeline is not a list: %s (type: %s) from %s',
173+
pipeline, type(pipeline).__name__, source)
153174
# Fallback to a basic pipeline
154175
pipeline = mm_cfg.GLOBAL_PIPELINE
155176

0 commit comments

Comments
 (0)