-
Notifications
You must be signed in to change notification settings - Fork 9
fix(transactions): return NotFoundError or (new) TypeMismatchError instead of StorageTransactionInconsistent where appropriate #1472
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Add transaction-explainer.md: High-level overview for newcomers - Explains core architecture (StorageTransaction, Journal, Chronicle) - Covers key design principles (write isolation, read consistency) - Documents transaction lifecycle and usage patterns - Add transaction-implementation-guide.md: Detailed guide for maintainers - Documents state machines and transitions - Explains critical implementation patterns - Details error states and handling - Covers key algorithms (consistency checking, write merging) - Includes performance considerations and testing guidelines 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…types Align transaction implementation with transaction-shim.ts behavior by returning appropriate errors for different failure scenarios. Key change: StorageTransactionInconsistent errors now only occur when the underlying state has changed, maintaining the invariant that retrying after this error will see different data. This is the key indicator for when to retry a transaction. - Introduce TypeMismatchError for accessing properties on non-objects (e.g., reading string.property or null.field) - Return NotFoundError when documents or paths don't exist, instead of inconsistency errors - Fix bug where writes to nested paths of documents created in the same transaction would incorrectly fail with NotFoundError - Update all tests to expect appropriate error types - Update documentation to explain error type distinctions 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…cefully The transaction shim's readOrThrow and writeOrThrow methods now treat TypeMismatchError like NotFoundError, returning undefined instead of throwing. This maintains backwards compatibility while leveraging the new distinct error types. Key changes: - validateParentPath now returns TypeMismatchError for type mismatches - readOrThrow returns undefined for both NotFoundError and TypeMismatchError - writeOrThrow handles both error types when creating parent entries - Updated tests to expect the correct error types 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
|
Now we have 806 tests passing, 113 failing! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR enhances the storage transaction system by introducing a new TypeMismatchError to distinguish between type mismatches (accessing properties on non-objects) and actual data inconsistencies. Previously, both scenarios were reported as StorageTransactionInconsistent, making it difficult to determine whether retries would help.
- Introduces
ITypeMismatchErrorinterface and implementation for persistent type errors - Updates error handling across transaction modules to use appropriate error types
- Adds comprehensive documentation explaining the transaction system architecture
Reviewed Changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/runner/test/transaction.test.ts | Updates test expectations from StorageTransactionInconsistent to TypeMismatchError for type mismatches |
| packages/runner/test/transaction-notfound.test.ts | New comprehensive test suite covering NotFound error scenarios and type mismatches |
| packages/runner/test/storage-transaction-shim.test.ts | Updates error expectations and messages for improved error distinction |
| packages/runner/test/journal.test.ts | Updates test expectations for type mismatch scenarios |
| packages/runner/test/chronicle.test.ts | Updates test expectations and adds proper type casting for ReadOnlyAddressError |
| packages/runner/test/attestation.test.ts | Updates error handling tests to expect TypeMismatchError and revised error messages |
| packages/runner/src/storage/transaction/chronicle.ts | Adds NotFoundError handling and converts errors during commit for consistency |
| packages/runner/src/storage/transaction/attestation.ts | Implements new TypeMismatchError class and updates error handling logic |
| packages/runner/src/storage/transaction-shim.ts | Enhances path validation to distinguish between NotFound and TypeMismatch errors |
| packages/runner/src/storage/transaction-implementation-guide.md | New detailed implementation guide for developers working on the transaction system |
| packages/runner/src/storage/transaction-explainer.md | New user-facing documentation explaining the transaction system architecture |
| packages/runner/src/storage/interface.ts | Adds ITypeMismatchError interface and updates error type unions |
Comments suppressed due to low confidence (2)
packages/runner/test/transaction-notfound.test.ts:12
- [nitpick] The class name 'MockReplica' is generic. Consider a more descriptive name like 'TestSpaceReplica' or 'InMemoryTestReplica' to better indicate its purpose as a test fixture.
class MockReplica implements ISpaceReplica {
packages/runner/test/transaction-notfound.test.ts:38
- [nitpick] The class name 'MockStorageManager' is generic. Consider a more descriptive name like 'TestStorageManager' or 'InMemoryStorageManager' to better indicate its test-specific implementation.
class MockStorageManager implements IStorageManager {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cubic analysis
2 issues found across 12 files • Review in cubic
React with 👍 or 👎 to teach cubic. You can also tag @cubic-dev-ai to give feedback, ask questions, or re-run the review.
| if (writeResult.error && writeResult.error.name === "NotFoundError") { | ||
| if (writeResult.error && | ||
| (writeResult.error.name === "NotFoundError" || | ||
| writeResult.error.name === "TypeMismatchError")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
writeOrThrow incorrectly handles TypeMismatchError as if it were NotFoundError, which can overwrite existing non-object values and mask real errors
Prompt for AI agents
Address the following comment on packages/runner/src/storage/transaction-shim.ts at line 687:
<comment>writeOrThrow incorrectly handles TypeMismatchError as if it were NotFoundError, which can overwrite existing non-object values and mask real errors</comment>
<file context>
@@ -644,9 +682,13 @@ export class ExtendedStorageTransaction implements IExtendedStorageTransaction {
value: JSONValue | undefined,
): void {
const writeResult = this.tx.write(address, value);
- if (writeResult.error && writeResult.error.name === "NotFoundError") {
+ if (writeResult.error &&
+ (writeResult.error.name === "NotFoundError" ||
+ writeResult.error.name === "TypeMismatchError")) {
// Create parent entries if needed
- const lastValidPath = writeResult.error.path;
</file context>
| if (readResult.error && readResult.error.name !== "NotFoundError") { | ||
| if (readResult.error && | ||
| readResult.error.name !== "NotFoundError" && | ||
| readResult.error.name !== "TypeMismatchError") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
readOrThrow treats TypeMismatchError as non-fatal, swallowing a persistent error that should be thrown
Prompt for AI agents
Address the following comment on packages/runner/src/storage/transaction-shim.ts at line 653:
<comment>readOrThrow treats TypeMismatchError as non-fatal, swallowing a persistent error that should be thrown</comment>
<file context>
@@ -612,7 +648,9 @@ export class ExtendedStorageTransaction implements IExtendedStorageTransaction {
options?: IReadOptions,
): JSONValue | undefined {
const readResult = this.tx.read(address, options);
- if (readResult.error && readResult.error.name !== "NotFoundError") {
+ if (readResult.error &&
+ readResult.error.name !== "NotFoundError" &&
+ readResult.error.name !== "TypeMismatchError") {
throw readResult.error;
}
</file context>
…hError handling - Update storage.test.ts to work with new transaction system (shim=false) - Remove sync() calls and add explicit commits before querying - Add conditional sync() calls only when shim is true - Wait for storage processing with runtime.idle() after commits - Fix data structure expectations to match new format - Update storage-transaction-shim.test.ts expectations - Change line 309 to expect TypeMismatchError instead of NotFoundError - This aligns with the shim behavior that distinguishes type mismatches - Previously updated transaction-shim.ts to treat TypeMismatchError like NotFoundError - Both error types are now handled gracefully in readOrThrow and writeOrThrow 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…ions
Updated test expectations to match the new subscription behavior where
'before' and 'after' fields now always contain the full document rather
than just the value at the specified path.
Changes:
- Fixed reactive-dependencies tests to pass full document structure
- Updated storage-subscription tests to expect full document with wrapper
- Modified storage-transaction-shim tests for consistent document structure
- Adjusted expectations for empty documents to use {} instead of undefined
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cubic analysis
2 issues found across 19 files • Review in cubic
React with 👍 or 👎 to teach cubic. You can also tag @cubic-dev-ai to give feedback, ask questions, or re-run the review.
| export interface INotFoundError extends Error { | ||
| name: "NotFoundError"; | ||
| path?: MemoryAddressPathComponent[]; | ||
| from(space: MemorySpace): INotFoundError; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like we lost the source: IAttestation and address: IMemoryAddress fields here.
It's not clear if that was intentional or accidental, since the interface was double defined with half here, and half later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, and the implementation in NotFound actually sets those. Added.
|
|
||
| return { ok: patch }; | ||
| } else { | ||
| // Type mismatch - trying to write property on non-object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is somewhat outside the PR, but on line 82 of the new file, we cast what can probably be an array into a Record<string, JSONValue>.
This works here, where we don't know the type, but wouldn't be a valid cast if typescript knew it was an array (you'd have to do an as unknown).
The behavior is correct, and maybe it's intentional to avoid code duplication just to appease types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch. i added tighter checking for arrays as well now (key is either a >= 0 integer or 'length')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
some minor comments, but looks good to merge as is.
Update attestation.write() to properly handle array types: - Explicitly check for arrays using Array.isArray() - Only allow writing to arrays at: - Valid non-negative integer indices (0, 1, 2, etc.) - The 'length' property for array truncation - Return TypeMismatchError for invalid array operations Add comprehensive tests to validate the new behavior: - Writing to valid positive integer indices (0, 1, 10) - Writing to array 'length' property for truncation - TypeMismatchError for negative indices (-1) - TypeMismatchError for non-integer keys (1.5) - TypeMismatchError for string keys other than 'length' - Proper handling of sparse arrays This ensures arrays are treated distinctly from objects and prevents invalid array modifications while maintaining backwards compatibility. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Improve storage transaction error handling with distinct error types
This PR enhances the storage transaction system by introducing a new
TypeMismatchErrorto distinguish between different failure modes when accessing document properties. Previously, all such errors were reported asStorageTransactionInconsistent, which made it difficult to determine whether a retry would help.Problem
The storage transaction system previously conflated two distinct types of errors:
"string".property)Both were reported as
StorageTransactionInconsistent, but they have very different implications:Solution
This PR introduces a new
TypeMismatchErrorto clearly distinguish these cases:Key Changes
ITypeMismatchErrorto the storage interfaceTypeMismatchErrorlikeNotFoundErrorfor compatibilityError Types After This PR
StorageTransactionInconsistent- Read invariant violated (underlying state changed) - retry recommendedNotFoundError- Document or path doesn't exist - transient errorTypeMismatchError- Accessing properties on non-objects - persistent errorReadOnlyAddressError- Writing to data: URIs - persistent errorTesting
Documentation
Added two new documentation files:
transaction-explainer.md- High-level overview for userstransaction-implementation-guide.md- Detailed guide for maintainersThis change makes error handling more predictable and helps consumers make better decisions about whether to retry failed operations.
Summary by cubic
Improved storage transaction error handling by introducing a new TypeMismatchError and ensuring NotFoundError is returned when accessing non-existent documents or paths, instead of StorageTransactionInconsistent. This makes error types more precise and helps consumers decide when to retry operations.
Bug Fixes
Documentation