Skip to content

Conversation

@morgan-wowk
Copy link

@morgan-wowk morgan-wowk commented Jan 26, 2026

Description

Added error message normalization functionality to standardize error messages by extracting dynamic values (UUIDs, IDs, hashes, etc.) and replacing them with placeholders. This helps group similar errors that differ only in their dynamic values.

The implementation includes:

  • A normalizeErrorMessage function that extracts various types of dynamic values
  • Comprehensive test coverage for different error message patterns
  • Support for extracting UUIDs, numeric IDs, alphanumeric IDs, query parameters, hash values, and quoted strings
  • Message truncation for very long error messages

Type of Change

  • New feature
  • Improvement

Checklist

  • I have tested this does not break current pipelines / runs functionality
  • I have tested the changes on staging

Test Instructions

Run the test suite with npm test src/services/errorManagement/normalizeErrorMessage.test.ts to verify the functionality works as expected.

Copy link
Author

morgan-wowk commented Jan 26, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.


// Extract UUIDs
normalized = normalized.replace(
/\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(\/|$|\)|\s)/gi,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we abstract these into a variable so I know what the regex does? I know there is a comment, but I would rather have a named constant or something

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely. Good idea

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented

extractedValues: Record<string, string>;
} {
const extractedValues: Record<string, string> = {};
let counter = 1;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we name this counter variable something a little more obvious? What is it counting, errors? errorCount or something.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extractedValueIndex would be more appropriate

It is the index of the value extracted from the original message

Copy link
Author

@morgan-wowk morgan-wowk Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if abcd is replaced first, extractedValueIndex is 1. and it becomes var1 in the normalized output. Incrementing from there for every match and replacement.

Comment on lines 18 to 26
normalized = normalized.replace(
/\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(\/|$|\)|\s)/gi,
(_match, uuid, after) => {
const placeholder = `{var${counter}}`;
extractedValues[placeholder] = uuid;
counter++;
return `/${placeholder}${after}`;
},
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inline regex chains are hard to follow. Consider something like:

const NORMALIZATION_PATTERNS = {
  uuid: {
    pattern: /\/([0-9a-f]{8}-[0-9a-f]{4}-...)/gi,
    replacer: (_, uuid, after, placeholder) => `/${placeholder}${after}`,
  },
  numericPathId: {
    pattern: /\/(\d+)(\/|$|\)|\s)/g,
    replacer: (_, num, after, placeholder) => `/${placeholder}${after}`,
  },
  // ... etc
};

// Then just loop:
for (const { pattern, replacer } of Object.values(NORMALIZATION_PATTERNS)) {
  normalized = normalized.replace(pattern, (...args) => {
    const placeholder = `{var${counter++}}`;
    return replacer(...args, placeholder);
  });
}

Why:

  • Readable - pattern names explain intent without reading the regex

  • Testable - can unit test individual patterns in isolation

  • Maintainable - adding/modifying patterns is just editing the object, not hunting through a chain of .replace() calls

Not blocking, but would make future debugging much easier.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dig it. I'll be adding something like this

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented

Comment on lines 112 to 114
if (normalized.length > 200) {
normalized = normalized.substring(0, 197) + "...";
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets replace some of these magic numbers:

const MAX_MESSAGE_LENGTH = 200;
const MAX_MESSAGE_TRUNCATED_LENGTH = 197

There are a few more above as well

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented

Comment on lines 72 to 85
// Extract quoted strings
normalized = normalized.replace(/"([^"]+)"/g, (_match, content) => {
const placeholder = `{var${counter}}`;
extractedValues[placeholder] = content;
counter++;
return placeholder;
});

normalized = normalized.replace(/'([^']+)'/g, (_match, content) => {
const placeholder = `{var${counter}}`;
extractedValues[placeholder] = content;
counter++;
return placeholder;
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these be replaces with one? /["']([^"']+)["']/g

Copy link
Author

@morgan-wowk morgan-wowk Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current approach (two separate patterns):

  • /"([^"]+)"/g - matches "hello" ✓
  • /'([^']+)'/g - matches 'world' ✓
  • Won't match "mixed' or 'mixed" ✗

Suggested pattern /["']([^"']+)["']/g:

  • Matches "hello" ✓
  • Matches 'world' ✓
  • Also matches "mixed' and 'mixed" ✓ (probably not desirable)

For error message normalization, we likely want to extract properly quoted strings only, not strings with mismatched quotes. Mismatched quotes are often syntax errors or literal parts of the error message itself, not dynamic values we want to normalize.

Claude's recommendation: Keep the two separate patterns for correctness. The slight code duplication is worth ensuring we only extract properly quoted strings.

Let me know if you have strong feelings to the alternate approach

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented

@morgan-wowk morgan-wowk force-pushed the 01-26-feat_add_error_message_normalization_utility_add_utility_to_normalize_error_messages_by_extracting_dynamic_values_uuids_ids_hashes_etc._and_replacing_them_with_placeholders._this_enables_better_error_grouping_in_monitoring_tools branch 2 times, most recently from 3e8c8af to 1119b6f Compare January 28, 2026 18:47
@morgan-wowk morgan-wowk force-pushed the 01-26-chore_install_bugsnag_packages branch from eae3b11 to 8bd6752 Compare January 28, 2026 21:27
@morgan-wowk morgan-wowk force-pushed the 01-26-feat_add_error_message_normalization_utility_add_utility_to_normalize_error_messages_by_extracting_dynamic_values_uuids_ids_hashes_etc._and_replacing_them_with_placeholders._this_enables_better_error_grouping_in_monitoring_tools branch from 1119b6f to 7ab4019 Compare January 28, 2026 21:27
Add utility to normalize error messages by extracting dynamic values
(UUIDs, IDs, hashes, etc.) and replacing them with placeholders.
This enables better error grouping in monitoring tools.
@morgan-wowk morgan-wowk changed the base branch from 01-26-chore_install_bugsnag_packages to graphite-base/1694 January 28, 2026 21:58
@morgan-wowk morgan-wowk force-pushed the 01-26-feat_add_error_message_normalization_utility_add_utility_to_normalize_error_messages_by_extracting_dynamic_values_uuids_ids_hashes_etc._and_replacing_them_with_placeholders._this_enables_better_error_grouping_in_monitoring_tools branch from 7ab4019 to d7fc62b Compare January 28, 2026 21:58
@morgan-wowk morgan-wowk changed the base branch from graphite-base/1694 to master January 28, 2026 21:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants