Skip to content

Fix undefined reference error in SendFailed.tsx#5811

Open
peterinnesmsft wants to merge 2 commits intomicrosoft:mainfrom
peterinnesmsft:peinnes/SendFailedFix
Open

Fix undefined reference error in SendFailed.tsx#5811
peterinnesmsft wants to merge 2 commits intomicrosoft:mainfrom
peterinnesmsft:peinnes/SendFailedFix

Conversation

@peterinnesmsft
Copy link
Copy Markdown
Contributor

@peterinnesmsft peterinnesmsft commented Apr 22, 2026

Fixes #5812

Changelog Entry

Description

In Dynamics 365 Contact Center, an error has been discovered in our own telemetry which points to an error occurring within SendFailed.tsx. The stack trace is as follows:

TypeError: Cannot read properties of undefined (reading 'has')

GitHub Copilot analysis points to the following minified code as being the problem:

uE = () => {
   let [e] = cE(),           // sendStatusByActivityKey (Map)
       t = aE(),             // activity key resolver
       r = sE(),             // localization hook
       n = oE(),             // live region announcer
       // Build Set of failed activity keys:
       i = useMemo(() =>
         Array.from(e).reduce(
           (e, [r, n]) => n !== tE || Dy(t(r)) ? e : e.add(r),
           new Set()
         ), [t, e]),
       o = r("TRANSCRIPT_LIVE_REGION_SEND_FAILED_ALT"),
       a = rE(i),            // usePrevious(i) → undefined on 1st render
       s = useMemo(() => {
         if (i === a) return false;
         for (let e of i.keys())
           if (!a.has(e))     // 💥 a is undefined on first mount
             return true;
         return false;
       }, [i, a]);
   return useEffect(() => { s && n(o) }, [s, o, n]), null;
 };

Design

The issue appears to be caused on initial render of the web chat control; we still don't quite fully understand the exact condition, but it seems like this is due to the ordering of the underlying useRef in usePrevious starting as undefined, and only being updated after initial render in useEffect, meaning that on initial render we can hit an undefined reference on prevActivityKeysOfSendFailed.

Specific Changes

  • Update /component/src/hooks/internal/usePrevious.ts to match the duplicated implementation that allows for setting an initial value.
  • Update SendFailed.tsx to specify an empty Set as the default value in usePrevious for prevActivityKeysOfSendFailed.
  • Adding an explicit falsey check in hasNewSendFailed on prevActivityKeysOfSendFailed so that if it doesn't match activityKeysOfSendFailed and evaluates to false, we return true to indicate that a new send has indeed failed.

TODO: Need to address the below.

  • I have added tests and executed them locally
  • I have updated CHANGELOG.md
  • I have updated documentation

Review Checklist

This section is for contributors to review your work.

  • Accessibility reviewed (tab order, content readability, alt text, color contrast)
  • Browser and platform compatibilities reviewed
  • CSS styles reviewed (minimal rules, no z-index)
  • Documents reviewed (docs, samples, live demo)
  • Internationalization reviewed (strings, unit formatting)
  • package.json and package-lock.json reviewed
  • Security reviewed (no data URIs, check for nonce leak)
  • Tests reviewed (coverage, legitimacy)

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a first-render crash in the transcript “Send failed” live-region announcer by ensuring usePrevious can return a defined initial value and updating SendFailed.tsx to use that initial value.

Changes:

  • Updated packages/component’s internal usePrevious hook to support an initialValue overload (matching the API package implementation).
  • Updated SendFailed.tsx to pass an initial empty Set to usePrevious to avoid calling .has() on undefined.
  • Added a new prevActivityKeysOfSendFailed falsy-check (currently redundant given the initial value).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
packages/component/src/hooks/internal/usePrevious.ts Adds overloads + useRef(initialValue) to allow a defined previous value on first render.
packages/component/src/Transcript/LiveRegion/SendFailed.tsx Uses an initial empty Set for usePrevious to prevent undefined dereference in .has().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +55 to +58
if (!prevActivityKeysOfSendFailed) {
return true;
}

Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

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

prevActivityKeysOfSendFailed is always a Set<string> here because usePrevious is called with an initialValue. The if (!prevActivityKeysOfSendFailed) { return true; } branch is therefore dead code and (if it ever became reachable) would incorrectly return true even when activityKeysOfSendFailed is empty. Suggest removing this check entirely, or (if you intend to support an undefined previous value) change it to return activityKeysOfSendFailed.size > 0 instead of unconditionally true.

Suggested change
if (!prevActivityKeysOfSendFailed) {
return true;
}

Copilot uses AI. Check for mistakes.
@compulim
Copy link
Copy Markdown
Contributor

Please write a test to show how we previously failed the case. This will make sure the new code is fortifying things in proper places.

Also, instead of modifying usePrevious, which could have a big impact, we could simplify things by doing set?.has().

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.

Undefined reference in SendFailed.tsx - TypeError: Cannot read properties of undefined (reading 'has')

3 participants