Top 10 SharePoint REST write traps
Reads forgive a lot, writes do not: a wrong body, date or fallback can lose data while the response still says success. These ten write traps cost the most time to diagnose and the most data when missed.
- Drop __metadata from write bodies — odata=verbose needs OData v3, and SPHttpClient sends v4A classic 400 on write: __metadata bodies from old tutorials; the plain JSON form that works under SPHttpClient.Old-tutorial payloads 400 as plain JSON, and switching to odata=verbose 400s again under SPHttpClient, which sends odata-version: 4.0; write plain JSON without the type hint, or blank odata-version where the verbose…
- Silent catch-to-empty fallbacks + destructive writes = data lossA catch that returns an empty array feeding delete then insert wipes data; strict reads for any destructive operation.catch → [] + delete-then-insert = data loss; strict and safe reads (+ a settings read that hides its failure lets a full-object save overwrite the config with defaults)
- DateTime fields — write full ISO with a time zone, derive the day locallyDates without a time zone 400 and UTC reads shift the day; write full ISO and derive the calendar day where it was entered.No-timezone writes 400; UTC reads shift the day; read a day in the zone it was written in — including noon-UTC dates at UTC+12 to +14; a bare date in $filter is UTC midnight, so le drops the last day of a range
- REST DELETE on a list item is permanent — recycle() is the binThe usual DELETE skips both recycle bins; call recycle() when users expect to restore what they removed.The usual delete call skips BOTH recycle bins; /items(id)/recycle() is what a “restorable for 93 days” promise needs
- X-RequestDigest expires ~30 min after page load — but adding it by hand in SPFx makes things worseWrites on a long open page fail with security validation is invalid; refresh the digest, and do not override SPHttpClient's own.Writes 403 "security validation is invalid" on a long-open page; raw fetch needs a fresh digest from /_api/contextinfo, but in SPFx a hand-set header switches SPHttpClient's own digest and 403-recovery OFF
- Created/Modified on a document library won't stick — and the API says 200 while ignoring youA plain MERGE on Created or Modified reports 204 and stamps now; ValidateUpdateListItem with the right format is the only path.A plain MERGE reports 204 and SharePoint overwrites both with "now"; ValidateUpdateListItem + bNewDocumentUpdate is the only path that holds, it wants the web's locale format (the error message tells you which), reads…
- AddValidateUpdateItemUsingPath answers 200 when it creates nothing — while a write to a missing column is a loud 400AddValidateUpdateItemUsingPath returns 200 with field errors inside and creates nothing; always inspect the response body.Field errors sit inside a 200 and no item is created; a write to a missing column is a 400 on every path, never a silent drop
- Lookup and person fields — read with $expand, write with <Name>IdLookups are read with $expand and written through the NameId field; covers the query limit you hit with many lookups.Read via $expand + projections, write via Id; ~12-lookup query limit
- A Hyperlink column takes an object, not a stringA Hyperlink column needs an object with Url and Description; a plain string fails the whole save with 400.It reads back as { Description, Url } ([object Object], React #31) and a plain string fails the whole save with 400; one helper each way, 255-character address limit, scheme allowlist
- A decimal comma erases a Number column — Number('7,25') is NaN, JSON sends null, SharePoint answers 204A decimal comma becomes NaN, then null, and SharePoint empties the column with a 204; parse locale input before saving.Number('7,25') is NaN, JSON.stringify sends null, SharePoint answers 204 and empties the column (measured: 7.25 → null on edit); parse text input comma-aware and reject NaN