{"record":{"id":"a69a7707af7f2c29","repo":"weaviate/weaviate","slug":"merge-object-data","errorCode":null,"errorMessage":"merge object data","messagePattern":"merge object data","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"adapters/repos/db/shard_write_merge.go","lineNumber":177,"sourceCode":"\t\ts.asyncReplicationRWMux.RLock()\n\t\tdefer s.asyncReplicationRWMux.RUnlock()\n\n\t\tlock.Lock()\n\t\tdefer lock.Unlock()\n\n\t\tvar err error\n\t\tprevObj, err = fetchObject(bucket, idBytes)\n\t\tif err != nil {\n\t\t\treturn errors.Wrap(err, \"get bucket\")\n\t\t}\n\n\t\tif prevObj == nil {\n\t\t\treturn errObjectNotFound\n\t\t}\n\n\t\tobj, _, err = s.mergeObjectData(prevObj, merge)\n\t\tif err != nil {\n\t\t\treturn errors.Wrap(err, \"merge object data\")\n\t\t}\n\n\t\t// A property-only merge carries the previous version's vectors forward;\n\t\t// a dropped one must not be re-persisted into a new segment.\n\t\tstripDroppedVectors(class, obj)\n\n\t\tstatus, err = s.determineInsertStatus(prevObj, obj)\n\t\tif err != nil {\n\t\t\treturn errors.Wrap(err, \"check insert/update status\")\n\t\t}\n\n\t\tobj.DocID = status.docID\n\t\tif status.skipUpsert {\n\t\t\treturn nil\n\t\t}\n\n\t\tobjBytes, err := obj.MarshalBinaryDisk(s.index.Config.SkipWriteClassNameOnDisk)\n\t\tif err != nil {","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/weaviate/weaviate/blob/75aa4b6d11f8818305aafd4440b4e32794f7ca04/adapters/repos/db/shard_write_merge.go#L159-L195","documentation":"This wrapper is returned from Shard.mergeObjectInStorage when s.mergeObjectData fails while applying a PATCH (partial merge) to an existing object stored in the shard's LSM objects bucket. mergeObjectData deep-copies the previous object and overlays the merge document's primitive properties, references, PropertiesToDelete, and vectors (mergeProps). Notably, if the previous object is nil (should not happen here, since nil was rejected just above), mergeObjectData logs 'resurrecting a zombie object' and synthesizes an empty base object, so most failures come from the overlay logic itself.","triggerScenarios":"Calling PATCH /v1/objects/{class}/{id} (or the batch merge path) on an existing object whose stored properties cannot be cleanly overlaid, e.g. stored Properties() is neither nil nor map[string]interface{}, or an inconsistent stored object causes the overlay of PrimitiveSchema/References/Vectors to fail.","commonSituations":"Objects written by older Weaviate versions with a legacy on-disk property layout being merged by a newer version; corrupted or hand-migrated LSM object data; concurrent writes leaving a torn previous object state.","solutions":["Check the wrapped inner error in the log; it names the exact failing sub-step of the overlay","Verify the object exists and is readable via GET before retrying the PATCH","If the object looks corrupt, re-import (re-create) the affected object rather than patching it","Upgrade to a version where mergeProps handles the stored property type defensively"],"exampleFix":"// server-side wrapper is informational; ensure callers check the full error chain\nif err := client.Schema().MergeObject(ctx, mergeDoc); err != nil {\n    log.Printf(\"merge failed: %v\", err) // includes 'merge object data: <inner>'\n}","handlingStrategy":"try-catch","validationCode":"// before PATCH: confirm the object exists and decodes\nobj, err := client.Data().Getter().WithClassName(class).WithID(id).Do(ctx)\nif err != nil || obj == nil { return fmt.Errorf(\"cannot patch %s/%s: %v\", class, id, err) }","typeGuard":"func mergeableProps(obj map[string]interface{}) bool {\n    for k, v := range obj {\n        switch v.(type) {\n        case nil, string, bool, float64, int64, []interface{}, map[string]interface{}:\n        default:\n            fmt.Printf(\"unsupported stored property type for %q: %T\\n\", k, v)\n            return false\n        }\n    }\n    return true\n}","tryCatchPattern":"if err := mergeObject(ctx, class, id, patch); err != nil {\n    if strings.Contains(err.Error(), \"merge object data\") {\n        log.Warnf(\"merge overlay failed, falling back to full replace: %v\", err)\n        return replaceObjectFully(ctx, class, id, patch)\n    }\n    return err\n}","preventionTips":["GET the object and sanity-check its properties before patching","Keep client and server versions aligned to avoid legacy disk-format mismatches","Patch only properties declared in the collection schema","Re-import objects suspected of on-disk corruption instead of patching them"],"tags":["go","storage","merge","lsm"],"backgroundTag":"object-merge-failed","analyzedSha":"75aa4b6d11f8818305aafd4440b4e32794f7ca04","analyzedAt":"2026-09-04T14:58:20.392Z","contentChangedAt":"2026-09-04T14:58:20.392Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}