-
Notifications
You must be signed in to change notification settings - Fork 863
Description
Description
When using manage_scriptable_object modify action to set an ObjectReference property, passing a JSON object (e.g. {"guid": "..."} or {"path": "..."}) via value silently clears the reference instead of setting it. The response reports success: true, ok: true with the message "Cleared reference.", giving no indication of failure.
This is a silent data loss bug — the caller believes the operation succeeded, but the reference was destroyed.
Two sub-issues
- Silent data loss:
{"value": {"guid": "..."}}and{"value": {"path": "..."}}resolvenewReftonulland clear the field without any error or warning. - API inconsistency with
manage_components:manage_components.set_propertyuses{"value": {"guid": "..."}}for object references.manage_scriptable_objectrequires{"ref": {"guid": "..."}}instead. This undocumented inconsistency makes it very easy for AI agents and users to use the wrong format.
Root Cause
In ManageScriptableObject.cs (lines 738–799), the ObjectReference handler reads the "ref" key from the patch object:
var refObj = patchObj["ref"] as JObject; // ← reads "ref", not "value"
string refGuid = refObj?["guid"]?.ToString();
string refPath = refObj?["path"]?.ToString();When the caller passes {"value": {"guid": "..."}}:
patchObj["ref"]isnull→refObjisnullrefGuidandrefPathare bothnull- Falls through to the
objRefValue?.Type == JTokenType.Stringcheck (line 766) - But
objRefValueis aJObject, not aJTokenType.String→ skip newRefstaysnull→ reference silently cleared
Reproduction
Environment: unity-mcp v9.6.0, Unity 6000.3.10f1
Setup: EnemyData ScriptableObject with [SerializeField] private GameObject _visualPrefab field.
Step 1: Set a known good value (baseline)
{
"action": "modify",
"target": {"path": "Assets/ScriptableObjects/Enemies/SkeletonSoldier_Mid.asset"},
"patches": [{"path": "_visualPrefab", "ref": {"guid": "a18ddbbe71509274e9c0c45c6285e830"}}]
}Result: "Set reference (ref.guid)." — File shows guid: a18ddbbe... ✅
Step 2: Overwrite with value object format
{
"action": "modify",
"target": {"path": "Assets/ScriptableObjects/Enemies/SkeletonSoldier_Mid.asset"},
"patches": [{"path": "_visualPrefab", "value": {"guid": "a18ddbbe71509274e9c0c45c6285e830"}}]
}Response: success: true, ok: true, message: "Cleared reference." — File shows fileID: 0 ❌
Step 3: Same with path format
{
"patches": [{"path": "_visualPrefab", "value": {"path": "Assets/Prefabs/Enemies/Visuals/Enemy_SkeletonSoldier.prefab"}}]
}Response: success: true, ok: true, message: "Cleared reference." — File shows fileID: 0 ❌
Step 4: Reproduced on a different SO and field
Tested ProfessionData._projectilePrefab on Archer.asset — same result: value + JSON object silently clears the reference.
Working formats (for reference)
| Format | Result |
|---|---|
{"ref": {"guid": "xxx"}} |
✅ Set reference |
{"ref": {"path": "Assets/xxx.prefab"}} |
✅ Set reference |
{"value": "Assets/xxx.prefab"} (string) |
✅ Set reference (path-shorthand) |
{"value": "32-char-hex-guid"} (string) |
✅ Set reference (guid-shorthand) |
{"value": {"guid": "xxx"}} (object) |
❌ Silently clears |
{"value": {"path": "xxx"}} (object) |
❌ Silently clears |
Suggestions
-
When
valueis a JObject containingguidorpathkeys, treat it as an object reference (same asref), rather than silently resolving tonull. -
At minimum, return
ok: falsewith an error message like"value contains an object with guid/path keys — did you mean to use 'ref' instead of 'value'?"instead of silently clearing. -
Consider unifying the API with
manage_components, which usesvalue: {"guid": "..."}for object references. The current inconsistency between tools is a usability trap.
Related
- manage_components / manage_prefabs: Setting Sprite sub-asset references fails with path/guid — undocumented spriteName workaround required #949 — Sprite sub-asset reference documentation issue (different tool, similar category)