Skip to content

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

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

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions