Skip to content

Fixed Date values being cloned to {} in prepareStackForUser - #1046

Merged
9larsons merged 1 commit into
mainfrom
slars/errors-preserve-dates-4c0869
Oct 9, 2026
Merged

9larsons merged 1 commit into
mainfrom
slars/errors-preserve-dates-4c0869

Conversation

@9larsons

@9larsons 9larsons commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator

prepareStackForUser deep clones the error before Ghost renders it. The inline deepCloneValue that replaced @stdlib/utils-copy in a447d77 (#426) copies every non-array object as a plain object. A Date has no own enumerable keys, so any Date in errorDetails or context came out as {}.

UpdateCollisionError from @tryghost/bookshelf-collision puts clientUpdatedAt and serverUpdatedAt in errorDetails as Dates. As a result, every 409 collision response from Ghost's API has returned both as {}. Admin reports these collisions to Sentry to tell a concurrent writer apart from a retried save, and it needs the timestamps to do that.

deepCloneValue now clones a Date as a new Date with the same time, so it serializes to an ISO string again.

Scope: Buffer, typed arrays, Map, Set and RegExp were also preserved by @stdlib/utils-copy. They're left out because nothing in Ghost core puts them in errorDetails. Map, Set and RegExp also serialize to {} in JSON either way.

After release, Ghost needs its @tryghost/errors catalog pin in pnpm-workspace.yaml bumped from 3.4.1.

Test: a Date nested in errorDetails survives prepareStackForUser as a separate Date with equal time, and a JSON round trip gives the ISO string. The test fails without the fix.

prepareStackForUser deep clones the error before Ghost renders it, and
the inline deepCloneValue that replaced @stdlib/utils-copy in a447d77
copied every non-array object as a plain object. Date has no own
enumerable keys, so any Date in errorDetails or context came out as {}.

UpdateCollisionError from @tryghost/bookshelf-collision carries
clientUpdatedAt and serverUpdatedAt as Dates, so every 409 response
from Ghost's API has returned both as {}. Admin reports these
collisions to Sentry to tell a concurrent writer apart from a retried
save, which needs the timestamps.

Dates are now cloned as Dates, so they serialize to ISO strings again.
@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 91de24bd-f155-48f8-a3d6-29dfde2aeca5

📥 Commits

Reviewing files that changed from the base of the PR and between e5c9f6b and 19db3e9.


📒 Files selected for processing (2)
  • packages/errors/src/utils.ts
  • packages/errors/test/utils.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.



Walkthrough

deepCloneValue now clones Date instances as distinct Date objects with the same timestamp. A test verifies that prepareStackForUser preserves a Date in errorDetails and that it serializes to the expected ISO string.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~8 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 19db3

Collision timestamps are preserved through error preparation so clients can receive their ISO-formatted values. No actionable merge-blocking risk is evident in the reviewed change.

Architecture Summary

Architecture risk: 🔵 Low · up to 19db3

The change affects 1 system.

Changed systems: packages/errors

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — packages/errors (library) was modified; 2 changed files map to changed impact.

Before / after behavior

  • observed — Modified behavior in packages/errors/src/utils.ts: deepCloneValue now returns a distinct Date with the original timestamp for date inputs; previously, dates fell through to generic object cloning.
  • observed — Modified behavior in packages/errors/test/utils.test.ts: Adds a test asserting that prepareStackForUser preserves a Date value in errorDetails as a distinct Date with the same timestamp and expected ISO JSON serialization.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check Passed The title clearly and concisely identifies the main change: preserving Date values during cloning in prepareStackForUser.
Description check Passed The description directly explains the defect, impact, implementation, scope, and test coverage for the changeset.
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.


✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR

🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR


  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.19%. Comparing base (e5c9f6b) to head (19db3e9).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1046      +/-   ##
==========================================
+ Coverage   97.91%   98.19%   +0.27%     
==========================================
  Files          92       47      -45     
  Lines        3122     1939    -1183     
  Branches      550      372     -178     
==========================================
- Hits         3057     1904    -1153     
+ Misses         23       10      -13     
+ Partials       42       25      -17     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@9larsons
9larsons merged commit fb64e4f into main Oct 9, 2026
7 checks passed
@9larsons
9larsons deleted the slars/errors-preserve-dates-4c0869 branch October 9, 2026 12:58
9larsons added a commit to TryGhost/Ghost that referenced this pull request Oct 9, 2026
ref TryGhost/framework#1046

Since @tryghost/errors 3.0.1 replaced @stdlib/utils-copy with an inline
clone, prepareStackForUser turned any Date in errorDetails into {}. Every
409 UpdateCollisionError from the Admin API therefore returned
clientUpdatedAt and serverUpdatedAt as {}, which leaves the editor's
Sentry collision reports unable to tell a concurrent writer apart from
a retried save. 3.4.2 clones Dates as Dates, so both fields serialize
to ISO strings again.
9larsons added a commit to TryGhost/Ghost that referenced this pull request Oct 9, 2026
ref TryGhost/framework#1046

Picks up @tryghost/errors 3.4.2 and the framework patch releases that
came with it. Since @tryghost/errors 3.0.1 replaced @stdlib/utils-copy
with an inline clone, prepareStackForUser turned any Date in
errorDetails into {}. Every 409 UpdateCollisionError from the Admin API
therefore returned clientUpdatedAt and serverUpdatedAt as {}, which
leaves the editor's Sentry collision reports unable to tell a concurrent
writer apart from a retried save. 3.4.2 clones Dates as Dates, so both
fields serialize to ISO strings again.

The other framework packages only pick up the new @tryghost/errors.
9larsons added a commit to TryGhost/Ghost that referenced this pull request Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants