Skip to content

refactor(java): typed exception hierarchy#334

Merged
pratyush618 merged 3 commits into
masterfrom
refactor/java-exception-hierarchy
Jun 30, 2026
Merged

refactor(java): typed exception hierarchy#334
pratyush618 merged 3 commits into
masterfrom
refactor/java-exception-hierarchy

Conversation

@pratyush618

@pratyush618 pratyush618 commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Replaces blanket TaskitoException throws with a small typed hierarchy so
callers can catch the failure class that matters to them. Every new type
extends the root TaskitoException, so existing catch (TaskitoException)
keeps working — non-breaking.

New errors/ package

  • SerializationException (+ subclass CryptoException for sign/encrypt failures)
  • WorkflowException — workflow submit/track/compensation failures
  • LockException, ConfigurationException, WebhookException

Rewiring

~30 throw sites across serializers, locks, webhooks, workflows, dashboard, and
the producer/admin surface now throw the specific type. Native JNI boundary
errors stay base TaskitoException (their cause is opaque).

Tests

ExceptionHierarchyTest asserts each type is catchable as TaskitoException
and that the documented throw sites raise the specific subclass.

Prerequisite for the saga PR (compensation failures throw WorkflowException).
Rebased onto master after #333.

Summary by CodeRabbit

  • Bug Fixes
    • Improved error reporting by switching many SDK failures to clearer, category-specific exceptions across workflow execution, serialization/deserialization, signing/encryption, webhook delivery, locking, and dashboard responses.
    • Invalid JSON, corrupted signed payloads, missing workflow/payload details, and interrupted waits now surface more precise exception types and messages.
    • Workflow submission now fails fast with a WorkflowException for certain payloadless structural steps and missing required workflow step data.
  • New Features
    • Added dedicated exception classes (e.g., ConfigurationException, SerializationException, CryptoException, LockException, WebhookException, WorkflowException) to support finer-grained exception handling.

Add SerializationException (+ CryptoException), WorkflowException,
LockException, ConfigurationException, WebhookException under errors/,
all extending TaskitoException, and route the SDK's throw sites to them
so callers can catch a category or the base type.
Subtype relationships, and that serializers throw Serialization/Crypto.
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7cccae96-2c23-41b0-8551-050ae0f4eb37

📥 Commits

Reviewing files that changed from the base of the PR and between 6edc84e and ba1a3d7.

📒 Files selected for processing (1)
  • sdks/java/src/main/java/org/byteveda/taskito/DefaultTaskito.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • sdks/java/src/main/java/org/byteveda/taskito/DefaultTaskito.java

📝 Walkthrough

Walkthrough

Six new exception types are added under org.byteveda.taskito.errors, and existing workflow, serialization, webhook, lock, configuration, and dashboard failure paths now throw those more specific types. Tests are added for exception inheritance and serializer failure behavior.

Changes

Typed Exception Hierarchy

Layer / File(s) Summary
New exception classes and package docs
sdks/java/src/main/java/org/byteveda/taskito/errors/SerializationException.java, errors/CryptoException.java, errors/WorkflowException.java, errors/ConfigurationException.java, errors/LockException.java, errors/WebhookException.java, errors/package-info.java
Defines the new exception subclasses under TaskitoException and adds package-level Javadoc for the errors package.
Serialization and crypto throw-site updates
sdks/java/src/main/java/org/byteveda/taskito/serialization/JsonSerializer.java, serialization/EncryptedSerializer.java, serialization/SignedSerializer.java, events/EventName.java, model/JobStatus.java
Updates serialization, encryption, signing, and wire-format parsing failures to throw SerializationException or CryptoException instead of TaskitoException.
Workflow and worker throw-site updates
sdks/java/src/main/java/org/byteveda/taskito/workflows/WorkflowTracker.java, workflows/WorkflowRun.java, worker/Worker.java, DefaultTaskito.java
Updates workflow tracking, run polling, worker option encoding, and workflow submission/encoding paths to throw WorkflowException or SerializationException.
Configuration, lock, webhook, and dashboard throw-site updates
sdks/java/src/main/java/org/byteveda/taskito/Taskito.java, locks/Lock.java, webhooks/Deliverer.java, webhooks/WebhookManager.java, webhooks/WebhookStore.java, dashboard/DashboardServer.java
Updates builder configuration, lock interruption, webhook signing/encoding/persistence, and dashboard JSON encoding to throw ConfigurationException, LockException, WebhookException, or SerializationException.
Exception hierarchy and behavior tests
sdks/java/src/test/java/org/byteveda/taskito/ExceptionHierarchyTest.java
Adds tests asserting inheritance relationships and that malformed or tampered payloads throw SerializationException and CryptoException.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • ByteVeda/taskito#306: Touches WorkflowTracker, which this PR updates to use WorkflowException and SerializationException.
  • ByteVeda/taskito#308: Adds submit-time workflow payload handling that this PR’s DefaultTaskito.submitWorkflow(...) validation now references.

Poem

🐇 I hopped through exceptions, neat and bright,
WorkflowException and friends in sight.
No more vague TaskitoException dust,
Just tidy types I can trust. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: introducing a typed Java exception hierarchy and replacing broad TaskitoException throws.
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
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/java-exception-hierarchy

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

@pratyush618

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
sdks/java/src/main/java/org/byteveda/taskito/serialization/EncryptedSerializer.java (1)

31-43: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve delegate SerializationExceptions here.

delegate.serialize(value) is inside the crypto try, so a plain payload-serialization failure now gets wrapped as CryptoException. That collapses the distinction this PR is introducing: callers using EncryptedSerializer can no longer tell “couldn’t serialize the payload” from “encryption failed.”

Suggested fix
 `@Override`
 public byte[] serialize(Object value) {
+    byte[] plaintext = delegate.serialize(value);
     try {
         byte[] iv = new byte[IV_LENGTH];
         random.nextBytes(iv);
         Cipher cipher = Cipher.getInstance(TRANSFORMATION);
         cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(TAG_BITS, iv));
-        byte[] ciphertext = cipher.doFinal(delegate.serialize(value));
+        byte[] ciphertext = cipher.doFinal(plaintext);
         byte[] out = new byte[IV_LENGTH + ciphertext.length];
         System.arraycopy(iv, 0, out, 0, IV_LENGTH);
         System.arraycopy(ciphertext, 0, out, IV_LENGTH, ciphertext.length);
         return out;
     } catch (Exception e) {
         throw new CryptoException("encryption failed", e);
     }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@sdks/java/src/main/java/org/byteveda/taskito/serialization/EncryptedSerializer.java`
around lines 31 - 43, The `EncryptedSerializer.serialize` method is catching
`delegate.serialize(value)` failures together with encryption errors, which
wraps plain payload serialization problems as `CryptoException`. Split the
handling in `serialize` so the `delegate.serialize(value)` call is allowed to
surface its `SerializationException` unchanged, and only the
cipher/IV/encryption steps are wrapped in `CryptoException`; keep the change
localized to `EncryptedSerializer` and preserve the existing crypto error path.
🧹 Nitpick comments (1)
sdks/java/src/test/java/org/byteveda/taskito/ExceptionHierarchyTest.java (1)

31-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the other remapped throw sites in this cohort.

This test file proves JsonSerializer and SignedSerializer, but the PR also changes EncryptedSerializer and JobStatus.fromWire(...). A regression in either public contract would still pass this suite.

Possible additions
+import org.byteveda.taskito.model.JobStatus;
+import org.byteveda.taskito.serialization.EncryptedSerializer;
     `@Test`
     void tamperedSignedPayloadThrowsCryptoException() {
         Serializer signed = new SignedSerializer(new JsonSerializer(), "secret".getBytes());
         byte[] bytes = signed.serialize(42);
         bytes[0] ^= 0x01; // corrupt the HMAC tag
@@
         assertInstanceOf(SerializationException.class, error);
         assertInstanceOf(TaskitoException.class, error);
     }
+
+    `@Test`
+    void tamperedEncryptedPayloadThrowsCryptoException() {
+        Serializer encrypted = new EncryptedSerializer(new JsonSerializer(), "0123456789abcdef".getBytes());
+        byte[] bytes = encrypted.serialize(42);
+        bytes[bytes.length - 1] ^= 0x01;
+
+        assertThrows(CryptoException.class, () -> encrypted.deserialize(bytes, Integer.class));
+    }
+
+    `@Test`
+    void unknownJobStatusThrowsSerializationException() {
+        assertThrows(SerializationException.class, () -> JobStatus.fromWire("bogus"));
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdks/java/src/test/java/org/byteveda/taskito/ExceptionHierarchyTest.java`
around lines 31 - 47, Add tests in ExceptionHierarchyTest to cover the other
remapped throw sites in this cohort: verify EncryptedSerializer.deserialize
throws the expected exception type on bad or tampered input, and verify
JobStatus.fromWire(...) maps invalid wire values to the correct exception
category. Use the existing patterns in
malformedPayloadThrowsSerializationException() and
tamperedSignedPayloadThrowsCryptoException() to keep the assertions aligned with
the public contracts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sdks/java/src/main/java/org/byteveda/taskito/DefaultTaskito.java`:
- Around line 382-383: The nested workflow validation path in DefaultTaskito is
still throwing TaskitoException from encodeChild(), which leaves
submitWorkflow(...) with mixed exception types for the same validation failure.
Update encodeChild() and any related child-step validation in DefaultTaskito to
throw WorkflowException consistently, matching the existing submit-time check
for missing payloads. Keep the exception messages descriptive for the invalid
child step so callers can catch WorkflowException for all workflow validation
failures.

---

Outside diff comments:
In
`@sdks/java/src/main/java/org/byteveda/taskito/serialization/EncryptedSerializer.java`:
- Around line 31-43: The `EncryptedSerializer.serialize` method is catching
`delegate.serialize(value)` failures together with encryption errors, which
wraps plain payload serialization problems as `CryptoException`. Split the
handling in `serialize` so the `delegate.serialize(value)` call is allowed to
surface its `SerializationException` unchanged, and only the
cipher/IV/encryption steps are wrapped in `CryptoException`; keep the change
localized to `EncryptedSerializer` and preserve the existing crypto error path.

---

Nitpick comments:
In `@sdks/java/src/test/java/org/byteveda/taskito/ExceptionHierarchyTest.java`:
- Around line 31-47: Add tests in ExceptionHierarchyTest to cover the other
remapped throw sites in this cohort: verify EncryptedSerializer.deserialize
throws the expected exception type on bad or tampered input, and verify
JobStatus.fromWire(...) maps invalid wire values to the correct exception
category. Use the existing patterns in
malformedPayloadThrowsSerializationException() and
tamperedSignedPayloadThrowsCryptoException() to keep the assertions aligned with
the public contracts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 20bcce17-9bc9-4767-9ae9-1681db8da9a0

📥 Commits

Reviewing files that changed from the base of the PR and between 8c2ae04 and 6edc84e.

📒 Files selected for processing (23)
  • sdks/java/src/main/java/org/byteveda/taskito/DefaultTaskito.java
  • sdks/java/src/main/java/org/byteveda/taskito/Taskito.java
  • sdks/java/src/main/java/org/byteveda/taskito/dashboard/DashboardServer.java
  • sdks/java/src/main/java/org/byteveda/taskito/errors/ConfigurationException.java
  • sdks/java/src/main/java/org/byteveda/taskito/errors/CryptoException.java
  • sdks/java/src/main/java/org/byteveda/taskito/errors/LockException.java
  • sdks/java/src/main/java/org/byteveda/taskito/errors/SerializationException.java
  • sdks/java/src/main/java/org/byteveda/taskito/errors/WebhookException.java
  • sdks/java/src/main/java/org/byteveda/taskito/errors/WorkflowException.java
  • sdks/java/src/main/java/org/byteveda/taskito/errors/package-info.java
  • sdks/java/src/main/java/org/byteveda/taskito/events/EventName.java
  • sdks/java/src/main/java/org/byteveda/taskito/locks/Lock.java
  • sdks/java/src/main/java/org/byteveda/taskito/model/JobStatus.java
  • sdks/java/src/main/java/org/byteveda/taskito/serialization/EncryptedSerializer.java
  • sdks/java/src/main/java/org/byteveda/taskito/serialization/JsonSerializer.java
  • sdks/java/src/main/java/org/byteveda/taskito/serialization/SignedSerializer.java
  • sdks/java/src/main/java/org/byteveda/taskito/webhooks/Deliverer.java
  • sdks/java/src/main/java/org/byteveda/taskito/webhooks/WebhookManager.java
  • sdks/java/src/main/java/org/byteveda/taskito/webhooks/WebhookStore.java
  • sdks/java/src/main/java/org/byteveda/taskito/worker/Worker.java
  • sdks/java/src/main/java/org/byteveda/taskito/workflows/WorkflowRun.java
  • sdks/java/src/main/java/org/byteveda/taskito/workflows/WorkflowTracker.java
  • sdks/java/src/test/java/org/byteveda/taskito/ExceptionHierarchyTest.java

Comment thread sdks/java/src/main/java/org/byteveda/taskito/DefaultTaskito.java
@pratyush618 pratyush618 merged commit eabda68 into master Jun 30, 2026
19 checks passed
@pratyush618 pratyush618 deleted the refactor/java-exception-hierarchy branch June 30, 2026 03:55
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.

1 participant