stride3d/stride · error · KeyNotFoundException
Unable to find the non-value type key in the dictionary of c
Error message
Unable to find the non-value type key in the dictionary of cloned keys.
What it means
CollectionItemIdentifiers.CloneInto copies the identifier state into a target instance. For reference-type keys it relies on a dictionary of previously cloned keys (referenceTypeClonedKeys) populated during the clone session; when it encounters a key that was never registered there, it cannot map the key into the clone and throws KeyNotFoundException. This prevents silently creating a clone whose items reference untracked keys.
Solutions
- Ensure every item is cloned via the same CollectionItemIdentifiers instance's Clone before CloneInto, so all reference-type keys are registered in referenceTypeClonedKeys.
- Re-run the full clone operation (fresh Clone followed immediately by CloneInto) instead of reusing a stale clone-state object.
- Verify no items were added or removed between Clone and CloneInto; snapshot the collection first.
- As a workaround, construct a new CollectionItemIdentifiers and re-add each item with a fresh id rather than patching clone state.
Example fix
// before: items added after Clone are unknown to referenceTypeClonedKeys var cloneState = identifiers.Clone(); identifiers.Add(ItemId.New(), newItem); identifiers.CloneInto(cloneState); // after: add items before cloning, or start a fresh clone session identifiers.Add(ItemId.New(), newItem); var cloneState = identifiers.Clone(); identifiers.CloneInto(cloneState);
Defensive patterns
Strategy: try-catch
Validate before calling
if (!identifiers.TryGetValue(key.Key, out _))
throw new InvalidOperationException($"Key {key.Key} was not registered by Clone before CloneInto"); Try / catch
try { identifiers.CloneInto(target); }
catch (KeyNotFoundException) { identifiers = new CollectionItemIdentifiers(); /* restart clone session */ } Prevention
- Perform Clone and CloneInto back-to-back with no mutation in between
- Never share reference-type keys across independent clone sessions
- Snapshot collections before cloning workflows
- Re-create clone state instead of reusing stale objects
When it happens
Trigger: Calling CloneInto when the source collection contains an object key that was never passed through Clone (so referenceTypeClonedKeys has no entry for it) — e.g. items added to the collection after cloning began, or keys shared across multiple collections where only one was cloned.
Common situations: Deep-cloning a package/asset whose identified collection gained new entries between the Clone and CloneInto calls; cloning two collections that share the same key objects; partially completed clone workflows in editor tooling.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- No Collection item identifier associated to the given collec
- Value cannot be null. (Parameter 'part')
- The guid of the key does not match the guid of the value
- Package RootDirectory is null
- Asset already exist in this collection
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/bcb3918829c32eab.
Report an issue: GitHub.
Appendix: source
Thrown at sources/assets/Stride.Core.Assets/Reflection/CollectionItemIdentifiers.cs:164
}
public void CloneInto(CollectionItemIdentifiers target, IReadOnlyDictionary<object, object>? referenceTypeClonedKeys)
{
target.keyToIdMap.Clear();
target.deletedItems.Clear();
foreach (var key in keyToIdMap)
{
if (key.Key.GetType().IsValueType || referenceTypeClonedKeys == null)
{
target.Add(key.Key, key.Value);
}
else if (referenceTypeClonedKeys.TryGetValue(key.Key, out var clonedKey))
{
target.Add(clonedKey, key.Value);
}
else
{
throw new KeyNotFoundException("Unable to find the non-value type key in the dictionary of cloned keys.");
}
}
foreach (var deletedItem in DeletedItems)
{
target.MarkAsDeleted(deletedItem);
}
}
public bool IsDeleted(ItemId itemId)
{
return DeletedItems.Contains(itemId);
}
public IEnumerator<KeyValuePair<object, ItemId>> GetEnumerator() => keyToIdMap.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
View on GitHub (pinned to 96fad776d2)