From aa46e0e668f8e9d1b69916f7f227f09696c47f43 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 5 Jul 2026 00:03:20 +1000 Subject: [PATCH] refactor: Remove unused internal field _tombstone `_tombstone` is a legacy Parse.com artifact that is never written, read, or queried by any Parse Server logic. Remove its dead entry from the `internalFields` registry in DatabaseController (whose only live effect was permitting master-key queries on a field nobody queries) and update the specs that referenced it. The `_tombstone` case in MongoTransform's `mongoObjectToParseObject` is intentionally kept: it is a defensive guard for documents created by old Parse Server / Parse.com versions that may still have the field persisted. Without it, such documents fall through to the `default` branch and throw "bad key in untransform" (see #570). A comment now documents this. Closes #10178 --- spec/ParseInstallation.spec.js | 1 - spec/RestQuery.spec.js | 12 ++++++------ spec/vulnerabilities.spec.js | 1 - src/Adapters/Storage/Mongo/MongoTransform.js | 7 ++++++- src/Controllers/DatabaseController.js | 1 - 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/spec/ParseInstallation.spec.js b/spec/ParseInstallation.spec.js index 261733c3af..66bb07cd0e 100644 --- a/spec/ParseInstallation.spec.js +++ b/spec/ParseInstallation.spec.js @@ -1295,7 +1295,6 @@ describe('Installations', () => { }); // TODO: Look at additional tests from installation_collection_test.go:882 - // TODO: Do we need to support _tombstone disabling of installations? // TODO: Test deletion, badge increments describe('deviceToken deduplication on new install (no installationId match)', () => { diff --git a/spec/RestQuery.spec.js b/spec/RestQuery.spec.js index 3438febf76..566d22861b 100644 --- a/spec/RestQuery.spec.js +++ b/spec/RestQuery.spec.js @@ -198,7 +198,6 @@ describe('rest query', () => { const internalFields = [ '_email_verify_token', '_perishable_token', - '_tombstone', '_email_verify_token_expires_at', '_failed_login_count', '_account_lockout_expires_at', @@ -222,10 +221,11 @@ describe('rest query', () => { user.setUsername('user1'); user.setPassword('password'); await user.signUp(); - // _tombstone is registered as an internal field but has no column in the - // Postgres _User table. Querying it with master key should return empty - // results (consistent with MongoDB behavior), not throw an error. - const results = await new Parse.Query(Parse.User).exists('_tombstone').find({ useMasterKey: true }); + // _session_token is registered as an internal field but has no column in + // the Postgres _User table (session tokens live in _Session). Querying it + // with master key should return empty results (consistent with MongoDB + // behavior), not throw an error. + const results = await new Parse.Query(Parse.User).exists('_session_token').find({ useMasterKey: true }); expect(results.length).toBe(0); }); @@ -234,7 +234,7 @@ describe('rest query', () => { user.setUsername('user1'); user.setPassword('password'); await user.signUp(); - const count = await new Parse.Query(Parse.User).exists('_tombstone').count({ useMasterKey: true }); + const count = await new Parse.Query(Parse.User).exists('_session_token').count({ useMasterKey: true }); expect(count).toBe(0); }); diff --git a/spec/vulnerabilities.spec.js b/spec/vulnerabilities.spec.js index 0e9c5aad21..3e75945478 100644 --- a/spec/vulnerabilities.spec.js +++ b/spec/vulnerabilities.spec.js @@ -3243,7 +3243,6 @@ describe('Vulnerabilities', () => { '_account_lockout_expires_at', '_password_changed_at', '_password_history', - '_tombstone', '_session_token', ]; diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index 0fd13017b3..7f4e94ca8f 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -1154,11 +1154,16 @@ const mongoObjectToParseObject = (className, mongoObject, schema) => { break; case '_acl': break; + // `_tombstone` is a legacy field that is no longer used by Parse Server, + // but documents created by old Parse Server / Parse.com versions may still + // have it persisted. It is kept here so those documents don't fall through + // to the `default` branch and throw "bad key in untransform". + // See https://github.com/parse-community/parse-server/issues/570 + case '_tombstone': case '_email_verify_token': case '_perishable_token': case '_perishable_token_expires_at': case '_password_changed_at': - case '_tombstone': case '_email_verify_token_expires_at': case '_account_lockout_expires_at': case '_failed_login_count': diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index d598cacac5..6986a47c7a 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -40,7 +40,6 @@ const internalFields = { _account_lockout_expires_at: { clientRead: false, masterRead: true, masterWrite: true }, _password_changed_at: { clientRead: false, masterRead: true, masterWrite: true }, _password_history: { clientRead: false, masterRead: true, masterWrite: true }, - _tombstone: { clientRead: false, masterRead: true, masterWrite: false }, _session_token: { clientRead: false, masterRead: true, masterWrite: false }, ///////////////////////////////////////////////////////////////////////////////////////////// // The following fields are not accessed by their _-prefixed name through the API;