Skip to content

Bug: MessageDecoder.decode discards default failure result when no plugin decodes #426

@kevinelliott

Description

@kevinelliott

Summary

MessageDecoder.decode() builds a sensible default result for the "no plugin matched" case (with error: 'No known decoder plugin for this message', the original message, full remaining.text, and decoder: { name: 'none', ... }), but then unconditionally overwrites that result with the return value of every plugin in the loop. If no plugin sets decoded: true, callers get the last plugin's return value — which has none of the diagnostic fields.

Affected code

lib/MessageDecoder.ts — the decode loop:

let result: DecodeResult = {
  decoded: false,
  error: 'No known decoder plugin for this message',
  decoder: { name: 'none', type: 'none', decodeLevel: 'none' },
  message: message,
  remaining: { text: message.text },
  raw: {},
  formatted: { description: 'Not Decoded', items: [] },
};

for (let i = 0; i < usablePlugins.length; i++) {
  const plugin = usablePlugins[i];
  result = plugin.decode(message, options);   // overwrites the default
  if (result.decoded) {
    break;
  }
}

return result;

When the loop finishes without a successful decode, result is whatever the last plugin returned. Per DecoderPlugin.defaultResult(), that result has:

  • no error field
  • no message field
  • decoder.name set to the plugin name (e.g. "label-44-pos"), suggesting falsely that that plugin handled the message
  • formatted.description set to "Unknown" rather than "Not Decoded"

Reproduction

Pass a message with a registered label whose payload doesn't match any plugin's pattern (e.g. label 44 with garbage text). The returned decoder.name will be the last Label_44_* plugin tried, and error / message will be missing.

Suggested fix

Track plugin returns in a temporary and only overwrite the default on a successful decode (or merge the diagnostic fields):

for (const plugin of usablePlugins) {
  const r = plugin.decode(message, options);
  if (r.decoded) {
    result = r;
    break;
  }
}
return result;

This also matches the "no plugin matched" semantics that the default object clearly intends.

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions