Change:
the block to inspect "Component" in DevTools : "Could not inspect element with id 5" Originally reported in https://user- Every time
Here's another Chrome extension build with the fix from :
Everything fixed. Awesome :+1:
FYI just published as 4.13.4

Discussion:
}); describe('inline errors and warnings', () => { <del> // Some actions require the Fiber id. // In those instances you might want to make assertions based on the ID instead of the index. function getErrorsAndWarningsForElement(id: number) { const index = ((store.getIndexOfElementID(id): any): number); return getErrorsAndWarningsForElementAtIndex(index); } </del> async function getErrorsAndWarningsForElementAtIndex(index) { const id = ((store.getElementIDAtIndex(index): any): number); <ins> if (id == null) { throw Error(`Element at index "${index}"" not found in store`); } </ins> let errors = null; let warnings = null;

jest.runOnlyPendingTimers(); let data = [ <del> await getErrorsAndWarningsForElement(1), await getErrorsAndWarningsForElement(2), </del> <ins> await getErrorsAndWarningsForElementAtIndex(0), await getErrorsAndWarningsForElementAtIndex(1), </ins> ]; expect(data).toMatchInlineSnapshot(` Array [

jest.runOnlyPendingTimers(); data = [ <del> await getErrorsAndWarningsForElement(1), await getErrorsAndWarningsForElement(2), </del> <ins> await getErrorsAndWarningsForElementAtIndex(0), await getErrorsAndWarningsForElementAtIndex(1), </ins> ]; expect(data).toMatchInlineSnapshot(` Array [

typeof setSuspenseHandler === 'function' && typeof scheduleUpdate === 'function'; <del> // Set of Fibers (IDs) with recently changed number of error/warning messages. const fibersWithChangedErrorOrWarningCounts: Set<number> = new Set(); </del> <ins> // Tracks Fibers with recently changed number of error/warning messages. // These collections store the Fiber rather than the ID, // in order to avoid generating an ID for Fibers that never get mounted // (due to e.g. Suspense or error boundaries). // onErrorOrWarning() adds Fibers and recordPendingErrorsAndWarnings() later clears them. const fibersWithChangedErrorOrWarningCounts: Set<Fiber> = new Set(); const pendingFiberToErrorsMap: Map<Fiber, Map<string, number>> = new Map(); const pendingFiberToWarningsMap: Map<Fiber, Map<string, number>> = new Map(); </ins> // Mapping of fiber IDs to error/warning messages and counts. <del> const fiberToErrorsMap: Map<number, Map<string, number>> = new Map(); const fiberToWarningsMap: Map<number, Map<string, number>> = new Map(); </del> <ins> const fiberIDToErrorsMap: Map<number, Map<string, number>> = new Map(); const fiberIDToWarningsMap: Map<number, Map<string, number>> = new Map(); </ins> function clearErrorsAndWarnings() { // eslint-disable-next-line no-for-of-loops/no-for-of-loops <del> for (const id of fiberToErrorsMap.keys()) { fibersWithChangedErrorOrWarningCounts.add(id); updateMostRecentlyInspectedElementIfNecessary(id); </del> <ins> for (const id of fiberIDToErrorsMap.keys()) { const fiber = idToArbitraryFiberMap.get(id); if (fiber != null) { fibersWithChangedErrorOrWarningCounts.add(fiber); updateMostRecentlyInspectedElementIfNecessary(id); } </ins> } // eslint-disable-next-line no-for-of-loops/no-for-of-loops <del> for (const id of fiberToWarningsMap.keys()) { fibersWithChangedErrorOrWarningCounts.add(id); updateMostRecentlyInspectedElementIfNecessary(id); </del> <ins> for (const id of fiberIDToWarningsMap.keys()) { const fiber = idToArbitraryFiberMap.get(id); if (fiber != null) { fibersWithChangedErrorOrWarningCounts.add(fiber); updateMostRecentlyInspectedElementIfNecessary(id); } </ins> } <del> fiberToErrorsMap.clear(); fiberToWarningsMap.clear(); </del> <ins> fiberIDToErrorsMap.clear(); fiberIDToWarningsMap.clear(); </ins> flushPendingEvents(); } <del> function clearErrorsForFiberID(id: number) { if (fiberToErrorsMap.has(id)) { fiberToErrorsMap.delete(id); fibersWithChangedErrorOrWarningCounts.add(id); flushPendingEvents(); } </del> <ins> function clearMessageCountHelper( fiberID: number, pendingFiberToMessageCountMap: Map<Fiber, Map<string, number>>, fiberIDToMessageCountMap: Map<number, Map<string, number>>, ) { const fiber = idToArbitraryFiberMap.get(fiberID); if (fiber != null) { // Throw out any pending changes. pendingFiberToErrorsMap.delete(fiber); </ins> <del> updateMostRecentlyInspectedElementIfNecessary(id); } </del> <ins> if (fiberIDToMessageCountMap.has(fiberID)) { fiberIDToMessageCountMap.delete(fiberID); // If previous flushed counts have changed, schedule an update too. fibersWithChangedErrorOrWarningCounts.add(fiber); flushPendingEvents(); </ins> <del> function clearWarningsForFiberID(id: number) { if (fiberToWarningsMap.has(id)) { fiberToWarningsMap.delete(id); fibersWithChangedErrorOrWarningCounts.add(id); flushPendingEvents(); </del> <ins> updateMostRecentlyInspectedElementIfNecessary(fiberID); } else { fibersWithChangedErrorOrWarningCounts.delete(fiber); } </ins> } <ins> } </ins> <del> updateMostRecentlyInspectedElementIfNecessary(id); </del> <ins> function clearErrorsForFiberID(fiberID: number) { clearMessageCountHelper( fiberID, pendingFiberToErrorsMap, fiberIDToErrorsMap, ); } function clearWarningsForFiberID(fiberID: number) { clearMessageCountHelper( fiberID, pendingFiberToWarningsMap, fiberIDToWarningsMap, ); </ins> } function updateMostRecentlyInspectedElementIfNecessary(

args: $ReadOnlyArray<any>, ): void { const message = format(...args); <del> // Note that by calling these functions we may be creating the ID for the first time. // If the Fiber is then never mounted, we are responsible for cleaning up after ourselves. // This is important because getOrGenerateFiberID() stores a Fiber in a couple of local Maps. // If the Fiber never mounts and we don't clean up after this code, we could leak. // Fortunately we would only leak Fibers that have errors/warnings associated with them, // which is hopefully only a small set and only in DEV mode– but this is still not great. // We should clean up Fibers like this when flushing; see recordPendingErrorsAndWarnings(). const fiberID = getOrGenerateFiberID(fiber); </del> if (__DEBUG__) { debug('onErrorOrWarning', fiber, null, `${type}: "${message}"`); } // Mark this Fiber as needed its warning/error count updated during the next flush. <del> fibersWithChangedErrorOrWarningCounts.add(fiberID); </del> <ins> fibersWithChangedErrorOrWarningCounts.add(fiber); </ins> <del> // Update the error/warning messages and counts for the Fiber. const fiberMap = type === 'error' ? fiberToErrorsMap : fiberToWarningsMap; const messageMap = fiberMap.get(fiberID); </del> <ins> // Track the warning/error for later. const fiberMap = type === 'error' ? pendingFiberToErrorsMap : pendingFiberToWarningsMap; const messageMap = fiberMap.get(fiber); </ins> if (messageMap != null) { const count = messageMap.get(message) || 0; messageMap.set(message, count + 1); } else { <del> fiberMap.set(fiberID, new Map([[message, 1]])); </del> <ins> fiberMap.set(fiber, new Map([[message, 1]])); </ins> } <del> // If this Fiber is currently being inspected, mark it as needing an udpate as well. updateMostRecentlyInspectedElementIfNecessary(fiberID); </del> // Passive effects may trigger errors or warnings too; // In this case, we should wait until the rest of the passive effects have run, // but we shouldn't wait until the next commit because that might be a long time.

function reevaluateErrorsAndWarnings() { fibersWithChangedErrorOrWarningCounts.clear(); <del> fiberToErrorsMap.forEach((countMap, fiberID) => { fibersWithChangedErrorOrWarningCounts.add(fiberID); </del> <ins> fiberIDToErrorsMap.forEach((countMap, fiberID) => { const fiber = idToArbitraryFiberMap.get(fiberID); if (fiber != null) { fibersWithChangedErrorOrWarningCounts.add(fiber); } </ins> }); <del> fiberToWarningsMap.forEach((countMap, fiberID) => { fibersWithChangedErrorOrWarningCounts.add(fiberID); </del> <ins> fiberIDToWarningsMap.forEach((countMap, fiberID) => { const fiber = idToArbitraryFiberMap.get(fiberID); if (fiber != null) { fibersWithChangedErrorOrWarningCounts.add(fiber); } </ins> }); recordPendingErrorsAndWarnings(); } <del> function recordPendingErrorsAndWarnings() { clearPendingErrorsAndWarningsAfterDelay(); </del> <ins> function mergeMapsAndGetCountHelper( fiber: Fiber, fiberID: number, pendingFiberToMessageCountMap: Map<Fiber, Map<string, number>>, fiberIDToMessageCountMap: Map<number, Map<string, number>>, ): number { let newCount = 0; </ins> <del> fibersWithChangedErrorOrWarningCounts.forEach(fiberID => { const fiber = idToArbitraryFiberMap.get(fiberID); if (fiber != null) { // Don't send updates for Fibers that didn't mount due to e.g. Suspense or an error boundary. // We may also need to clean up after ourselves to avoid leaks. // See inline comments in onErrorOrWarning() for more info. if (isFiberMountedImpl(fiber) !== MOUNTED) { untrackFiberID(fiber); return; } </del> <ins> let messageCountMap = fiberIDToMessageCountMap.get(fiberID); </ins> <del> let errorCount = 0; let warningCount = 0; </del> <ins> const pendingMessageCountMap = pendingFiberToMessageCountMap.get(fiber); if (pendingMessageCountMap != null) { if (messageCountMap == null) { messageCountMap = pendingMessageCountMap; </ins> <del> if (!shouldFilterFiber(fiber)) { const errorCountsMap = fiberToErrorsMap.get(fiberID); const warningCountsMap = fiberToWarningsMap.get(fiberID); </del> <ins> fiberIDToMessageCountMap.set(fiberID, pendingMessageCountMap); } else { // This Flow refinement should not be necessary and yet... const refinedMessageCountMap = ((messageCountMap: any): Map< string, number, >); pendingMessageCountMap.forEach((pendingCount, message) => { const previousCount = refinedMessageCountMap.get(message) || 0; refinedMessageCountMap.set(message, previousCount + pendingCount); }); } } </ins> <del> if (errorCountsMap != null) { errorCountsMap.forEach(count => { errorCount += count; }); } if (warningCountsMap != null) { warningCountsMap.forEach(count => { warningCount += count; }); } } </del> <ins> if (!shouldFilterFiber(fiber)) { if (messageCountMap != null) { messageCountMap.forEach(count => { newCount += count; }); } } pendingFiberToMessageCountMap.delete(fiber); return newCount; } function recordPendingErrorsAndWarnings() { clearPendingErrorsAndWarningsAfterDelay(); fibersWithChangedErrorOrWarningCounts.forEach(fiber => { const fiberID = getFiberIDUnsafe(fiber); if (fiberID === null) { // Don't send updates for Fibers that didn't mount due to e.g. Suspense or an error boundary. } else { const errorCount = mergeMapsAndGetCountHelper( fiber, fiberID, pendingFiberToErrorsMap, fiberIDToErrorsMap, ); const warningCount = mergeMapsAndGetCountHelper( fiber, fiberID, pendingFiberToWarningsMap, fiberIDToWarningsMap, ); </ins> pushOperation(TREE_OPERATION_UPDATE_ERRORS_OR_WARNINGS); pushOperation(fiberID); pushOperation(errorCount); pushOperation(warningCount); } <ins> // Always clean up so that we don't leak. pendingFiberToErrorsMap.delete(fiber); pendingFiberToWarningsMap.delete(fiber); </ins> }); fibersWithChangedErrorOrWarningCounts.clear(); }

rootType = fiberRoot._debugRootType; } <del> const errors = fiberToErrorsMap.get(id) || new Map(); const warnings = fiberToWarningsMap.get(id) || new Map(); </del> <ins> const errors = fiberIDToErrorsMap.get(id) || new Map(); const warnings = fiberIDToWarningsMap.get(id) || new Map(); </ins> return { id,