SigNoz/signoz · error
ErrCodeDashboardInvalidPatch
ErrCodeDashboardInvalidPatch
Error message
JSON Patch could not be applied to the target dashboard
What it means
Apply in perses_dashboard_patch.go runs a JSON Patch (RFC 6902) against the marshaled existing dashboard using patch.ApplyWithOptions with AllowMissingPathOnRemove and EnsurePathExistsOnAdd. If the evanphx/json-patch library rejects the operation sequence (unparseable patch, invalid op, path escaping failure, mismatched types), the error is wrapped as ErrCodeDashboardInvalidPatch with the underlying patch error attached via WithAdditional.
Solutions
- Validate the patch is a legal RFC 6902 document (jsonpatch.Decode) before applying
- Retry with a fresh GET of the dashboard and regenerate the patch against current state
- Check the attached underlying error (WithAdditional) to see the exact failing op and path
- Fall back to a full PUT/update instead of a patch if the path churn is expected
Example fix
// before
patch := []byte(`[{"op":"replace","path":"/panels/5","value":{}}]`)
updated, err := p.Apply(existing)
// after
patch := []byte(`[{"op":"replace","path":"/panels/5/title","value":"latency"}]`)
updated, err := p.Apply(existing) Defensive patterns
Strategy: validation
Validate before calling
if _, err := jsonpatch.DecodePatch(patchBytes); err != nil {
return fmt.Errorf("malformed patch: %w", err)
}
updated, err := p.Apply(existing) Try / catch
out, err := patch.Apply(existing)
if err != nil {
// re-fetch and regenerate patch once, then give up with a clear message
fresh := getLatestDashboard(id)
out, err = patch.Apply(fresh)
} Prevention
- Keep patch ops narrow (leaf paths like /panels/0/title)
- Build patches from a just-fetched copy of the resource
- Prefer full update over patch when schema versions differ
When it happens
Trigger: Calling PatchV2 (or Apply directly) with a JSON Patch document whose ops reference paths that do not match the dashboard structure (beyond what AllowMissingPathOnRemove/EnsurePathExistsOnAdd tolerate), use an unknown op, or try to replace/add a value of the wrong type at a path (e.g. replacing an array with an object).
Common situations: Clients generating patches from a stale copy of the dashboard (concurrent edits moved/renamed fields); patch tools emitting copy/move ops with malformed from paths; UI diffing after a dashboard schema upgrade between versions.
Related errors
- dashboard_invalid_patch
- CodeLicenseUnavailable
- dashboard_invalid_widget_query
- ErrCodeDashboardInvalidData
- ErrCodeDashboardInvalidData
AI-assisted analysis of SigNoz/signoz@5069bf80b0 (2026-08-28).
Data as JSON: /api/errors/35c95c4cd0670476.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/types/dashboardtypes/perses_dashboard_patch.go:76
if err != nil {
return errors.New(errors.TypeInvalidInput, ErrCodeDashboardInvalidPatch, "request body is not a valid RFC 6902 JSON Patch document").WithAdditional(err.Error())
}
if err := json.Unmarshal(data, &p.Ops); err != nil {
return errors.New(errors.TypeInvalidInput, ErrCodeDashboardInvalidPatch, "request body is not a valid RFC 6902 JSON Patch document").WithAdditional(err.Error())
}
p.patch = patch
return nil
}
func (p PatchableDashboardV2) Apply(existing *DashboardV2) (*UpdatableDashboardV2, error) {
existingAsUpdatable := existing.toUpdatableDashboardV2()
raw, err := json.Marshal(existingAsUpdatable)
if err != nil {
return nil, errors.WrapInternalf(err, errors.CodeInternal, "marshal existing dashboard for patch")
}
patched, err := p.patch.ApplyWithOptions(raw, &jsonpatch.ApplyOptions{AllowMissingPathOnRemove: true, EnsurePathExistsOnAdd: true})
if err != nil {
return nil, errors.Wrap(err, errors.TypeInvalidInput, ErrCodeDashboardInvalidPatch, "JSON Patch could not be applied to the target dashboard").WithAdditional(err.Error())
}
out := &UpdatableDashboardV2{}
if err := json.Unmarshal(patched, out); err != nil {
return nil, err
}
return out, nil
}
View on GitHub (pinned to 5069bf80b0)