{"record":{"id":"221539161baefa09","repo":"SigNoz/signoz","slug":"errcodeinvalidpatchobject","errorCode":"ErrCodeInvalidPatchObject","errorMessage":"empty object patch request received, at least one of additions or deletions must be present","messagePattern":"empty object patch request received, at least one of additions or deletions must be present","errorType":"validation","errorClass":"errors SigNozError","httpStatus":400,"severity":"warning","filePath":"pkg/types/coretypes/object.go","lineNumber":144,"sourceCode":"\t\tkey := obj.Resource.String()\n\t\tif _, ok := grouped[key]; !ok {\n\t\t\tgrouped[key] = &ObjectGroup{Resource: obj.Resource, Selectors: make([]Selector, 0)}\n\t\t\torder = append(order, key)\n\t\t}\n\t\tgrouped[key].Selectors = append(grouped[key].Selectors, obj.Selector)\n\t}\n\n\tobjectGroups := make([]*ObjectGroup, 0, len(order))\n\tfor _, key := range order {\n\t\tobjectGroups = append(objectGroups, grouped[key])\n\t}\n\n\treturn objectGroups\n}\n\nfunc NewPatchableObjects(additions []*ObjectGroup, deletions []*ObjectGroup, verb Verb) ([]*Object, []*Object, error) {\n\tif len(additions) == 0 && len(deletions) == 0 {\n\t\treturn nil, nil, errors.New(errors.TypeInvalidInput, ErrCodeInvalidPatchObject, \"empty object patch request received, at least one of additions or deletions must be present\")\n\t}\n\n\tfor _, objectGroup := range additions {\n\t\tif err := ErrIfVerbNotValidForResource(verb, objectGroup.Resource); err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t}\n\n\tfor _, objectGroup := range deletions {\n\t\tif err := ErrIfVerbNotValidForResource(verb, objectGroup.Resource); err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t}\n\n\tadditionObjects, err := NewObjectsFromObjectGroups(additions)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/SigNoz/signoz/blob/5069bf80b08f1f00d7e014eccc09902f9871004f/pkg/types/coretypes/object.go#L126-L162","documentation":"NewPatchableObjects builds object additions/deletions for a patch request; it refuses fully empty patches where both additions and deletions slices are empty, since a no-op patch is almost always a client bug.","triggerScenarios":"Calling the object patch API with {\"additions\":[],\"deletions\":[]} or omitting both arrays; programmatic patch builders that skip populating when a diff is empty.","commonSituations":"UI 'apply changes' button with no changes selected; diff calculators returning empty lists and still submitting; default-constructed request structs never filled.","solutions":["Skip the PATCH call entirely when both lists are empty","Ensure the diff logic actually maps changed groups into additions/deletions","Validate client-side: if additions+deletions==0, show 'no changes' instead of submitting","Check for accidental early-return in the code that populates the arrays"],"exampleFix":"// before\nif err := patchObjects(nil, nil, verb); err != nil { ... }\n// after\nif len(additions) == 0 && len(deletions) == 0 { return nil }\naddObjs, delObjs, err := coretypes.NewPatchableObjects(additions, deletions, verb)\n","handlingStrategy":"validation","validationCode":"if (additions.length === 0 && deletions.length === 0) { /* skip PATCH */ }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Guard no-op patches at the call site","Log diffs before submitting to catch empty diff bugs"],"tags":["patch","validation","objects","go"],"backgroundTag":"empty-patch-request","analyzedSha":"5069bf80b08f1f00d7e014eccc09902f9871004f","analyzedAt":"2026-08-28T06:22:12.824Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}