SigNoz/signoz · error
dashboard_invalid_patch
dashboard_invalid_patch
Error message
request body is not a valid RFC 6902 JSON Patch document
What it means
PatchableDashboardV2.UnmarshalJSON decodes the body both as an RFC 6902 JSON Patch (jsonpatch.DecodePatch) and as a typed Ops slice. This variant fires when DecodePatch fails: the body is not a JSON array of {op, path, value} operation objects.
Source
Thrown at pkg/types/dashboardtypes/perses_dashboard_patch.go:59
type PatchOp struct{ valuer.String }
var (
PatchOpAdd = PatchOp{valuer.NewString("add")}
PatchOpRemove = PatchOp{valuer.NewString("remove")}
PatchOpReplace = PatchOp{valuer.NewString("replace")}
PatchOpMove = PatchOp{valuer.NewString("move")}
PatchOpCopy = PatchOp{valuer.NewString("copy")}
PatchOpTest = PatchOp{valuer.NewString("test")}
)
func (PatchOp) Enum() []any {
return []any{PatchOpAdd, PatchOpRemove, PatchOpReplace, PatchOpMove, PatchOpCopy, PatchOpTest}
}
func (p *PatchableDashboardV2) UnmarshalJSON(data []byte) error {
patch, err := jsonpatch.DecodePatch(data)
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())
}View on GitHub (pinned to 5069bf80b0)
Solutions
- Send an RFC 6902 array: [{"op":"replace","path":"/title","value":"new"}]
- Use op values add/remove/replace/move/copy/test only
- Ensure each op has a valid path (JSON Pointer starting with /)
- Don't send the whole dashboard document to the PATCH endpoint
Example fix
// before
{"title":"new title"}
// after
[{"op":"replace","path":"/title","value":"new title"}]
Defensive patterns
Strategy: validation
Validate before calling
function isRFC6902(body: unknown): boolean {
return Array.isArray(body) && body.every(op => typeof op?.op === 'string' && typeof op?.path === 'string');
} Type guard
function isPatchDoc(b: unknown): b is Array<{op:string;path:string;value?:unknown}> { return isRFC6902(b); } Prevention
- Use a json-patch library client-side to build patches
- Don't confuse merge-patch with JSON Patch
When it happens
Trigger: PATCH dashboard request whose body is a JSON object (full dashboard), a bare object diff, or an array with entries missing op/path.
Common situations: Clients sending JSON Merge Patch (RFC 7386) style bodies instead of RFC 6902; wrong Content-Type handling proxying that mangles the body; assuming REST PUT semantics for PATCH.
Related errors
- invalid_input
- public_dashboard_invalid_input
- CodeInvalidInput
- ErrCodeRoleInvalidInput
- ErrCodeInvalidGatewayConfig
AI-assisted analysis of SigNoz/signoz@5069bf80b0 (2026-08-28).
Data as JSON: /api/errors/fe0f8dc963362462.
Report an issue: GitHub.