whoami

Lucas Jenß

cat /etc/motd

The Coding Journal ツ — Notes taken on an epic coding journey. Technical solutions, debugging notes, and practical guides from the trenches of software development.

Close-up of white dominoes with black dots standing on green felt surface, shallow depth of field, focused mood

ls -la ~/languages/

total 8
drwxr-xr-x
▶ PHP
▶ Ruby
▶ Scala
▶ C#
▶ JavaScript
▶ Objective-C
▶ Shell Scripting

ls -la ~/toolchain/

total 7
drwxr-xr-x
▶ Typo3
▶ Akka
▶ Capistrano
▶ Git
▶ MAMP
▶ Adobe Illustrator
▶ NSTrackingArea (Cocoa)

uname -a

platforms
drwxr-xr-x
▶ Mac OS X
▶ Unix

Sending Akka case classes without serialization breakage

Akka serialization issues when sending case classes over the wire usually begin at the boundary between an actor system and the network. A local actor exchange can look deceptively simple: one node sends an immutable case class to another actor, and both sides refer to the same Scala type. During remote delivery, that object becomes bytes, crosses the transport and must be reconstructed by the receiver. A mismatch in serializers, class definitions or dependencies then turns an ordinary message into an opaque failure.

The useful approach is to trace the message through that boundary rather than change code at random. Start with the exception and the class name, confirm how the payload is encoded, then compare the sender and receiver classpaths. Every step should produce evidence that narrows the fault.

Understand the failure boundary

Local delivery can bypass serialization when the recipient lives in the same actor system. Remote delivery cannot: the sending side selects a serializer, converts the message to a byte array, and the receiving side must locate the matching class before constructing it. That makes an apparently harmless refactor, such as renaming a package, capable of breaking communication between nodes.

Symptoms usually fall into a few groups. A failure while writing the payload points to an unsupported value or a serializer configuration problem. A ClassNotFoundException on receipt indicates a missing or differently named class. An InvalidClassException often signals incompatible Java-serialized definitions, while a Jackson UnrecognizedPropertyException can reveal a changed JSON contract.

Record the full stack trace, selected serializer, fully qualified class name and versions of the shared JARs on both nodes. My miscellaneous fixes notes cover smaller environment quirks, but this failure needs enough evidence to separate encoding trouble from deployment drift. Australian teams frequently span Sydney, Melbourne, Brisbane or Perth, so “it is working here” may refer to a genuinely different runtime.

Build a stable wire contract

Treat the case class as part of a wire contract, not merely an internal convenience. Keep its package name stable, place it in a shared module and record an explicit serialVersionUID when Java serialization remains enabled. Adding a field can alter the automatically generated identifier, so compatibility should be tested rather than assumed.

For JSON, decide how absent values, unknown properties and defaults behave before deploying. Jackson with Scala support handles immutable case classes, Option values and Scala collections, but its mapping rules still need to match the intended schema. For sealed traits, use a deliberate discriminator instead of an unconstrained Any field, otherwise two nodes may interpret the same payload differently.

Schema-first formats make evolution more visible. Protobuf keeps field numbers meaningful; Avro can resolve a new writer schema against an older reader schema. JSON remains convenient for inspection and mixed-language consumers, while binary schemas suit high-volume internal traffic. In Australian banking, logistics and government services, the operational cost of maintaining that contract often matters as much as raw throughput.

Configure serialization deliberately

Classic Akka remoting commonly falls back to Java serialization unless configured otherwise. On an existing system, set akka.actor.warn-about-java-serializer-usage = on to reveal the dependency, register an appropriate JSON or schema-based serializer and bind the relevant message classes to it. Once the migration is complete, akka.actor.allow-java-serialization = off can prevent accidental fallback.

The exact configuration depends on the Akka version, but the order is consistent: install the serializer library, define its configuration, apply the binding and restart both actor systems. Both nodes must also resolve the expected domain classes. A serializer on the classpath does not make a renamed or absent case class available to the deserializer.

Keep payloads limited to data that can survive a process boundary. Live actors, futures, streams, database sessions and file handles do not belong in a message envelope; represent collaborators or identifiers instead. A broad Any value may also conceal a wire contract that different nodes interpret differently. When a library’s error handling is opaque, Mike Patt is another programming reference I keep open alongside the source.

Test across real network conditions

A round-trip test inside one JVM is necessary but insufficient. Exercise two actor systems, first on separate ports and later on separate hosts or containers, using the same dependency set as production. Verify that the receiving node actually loads the intended class; a stale JAR or shaded artifact can make a corrected build appear unchanged.

Add compatibility tests with two application versions running together. Send known messages in both directions, assert the decoded values and store a small payload fixture that reveals encoding changes without exposing sensitive records. During rollout, keep old and new readers capable of accepting the agreed format until every node has migrated.

Australian conditions add useful stress to the story: an NBN connection may be excellent in one office and less reliable in another, while hosted workloads can sit in Sydney or Melbourne as developers test from elsewhere. A common Australian aside—“it works on my box”—is a clue, not proof. Correlate exceptions, node versions and timeout data before increasing timeouts, since a retry can also duplicate side effects.

Compare the main encoding choices

There is no universally best encoder. Compare candidates against the actual failure modes in your system rather than benchmark numbers alone. Java serialization offers a familiar baseline but carries brittle class compatibility and unsafe deserialization concerns. JSON is readable and easy to integrate, although payloads are larger and mapping choices matter. Kryo can be efficient, while Protobuf and Avro provide explicit schemas but require contract discipline.

Encoding Main advantage Typical risk Strong fit
Java serialization Minimal setup and native Java compatibility Class evolution and deserialization safety Controlled, short-lived internal deployments
JSON with Jackson Readable payloads and broad tooling Mapping drift and additional bytes Mixed-language services and modest volumes
Kryo Compact output with custom serializers Registration and compatibility changes High-volume controlled JVM traffic
Protobuf or Avro Explicit schemas and strong evolution rules Contract tooling and rollout overhead Stable service boundaries and high throughput

Security and operability narrow the choice further. Disable Java deserialization for untrusted traffic, keep actor-system authentication and transport encryption in place, and avoid logging complete business messages. A binary format may reduce bandwidth, yet base64 encoding and larger schema bundles have their own costs. Test rolling upgrades with the selected format before committing to it.

Make the fix durable in production

Before the next release, turn the investigation into a repeatable deployment check:

  • Capture the failing class name, fully qualified package, selected serializer, payload shape and complete exception from both sending and receiving nodes.
  • Compare shared dependencies and configuration, including serialVersionUID, mapper rules and schema versions; identical deployment scripts do not guarantee identical runtimes.
  • Run the mixed-version test and a transport test against separate nodes, then verify invalid messages fail cleanly rather than disappearing behind a generic timeout.
  • Roll out in stages, watch serialization failure rates alongside latency, and retain a rollback path until the older application version no longer receives traffic.

A durable fix needs both code and evidence. Move the message contract into a versioned shared module, record why that encoding was chosen and add the reproduction to the regression suite. Start with one failing message today: capture its details, rerun the compatibility test and publish the verified fix through The Coding Journal.


cat ~/interests.json

KeyValue
editorTerminal-first workflow
osMac OS X / Unix
vcsGit, distributed version control
deployCapistrano, cron automation
graphicsSVG, Adobe Illustrator troubleshooting
networkingIP validation, SSH, VPN

git log --oneline --reverse

2013-10-30

Solving SVG import issues in Adobe Illustrator CS6 and CC

When importing an SVG into Illustrator, the operation fails with an unknown error [CANT]. A workaround for this Adobe-side bug.

2013

Solving NDK build issues on OS X

Troubleshooting native development kit compilation problems on Mac OS X.

2013

Programmatically adding PHP generated TypoScript to the backend configuration

Integrating dynamically generated TypoScript into Typo3 backend setups using PHP.

2013

ArgumentError: Could not parse PKey: no start line

Debugging an SSH key parsing error encountered during deployment.

2011-08-04

Validating IP-Addresses in PHP

Using PHP filter functions with flags like FILTER_FLAG_IPV4 and FILTER_FLAG_IPV6, and understanding how filter_var handles reserved IP addresses.

2011-07-09

Cocoa: Using NSTrackingArea

A short tutorial on using Cocoa's NSTrackingArea to capture mouseEntered and mouseExited events.


cat ~/contact.txt

github: github.com/x3ro
stackoverflow: x3ro
coderwall: coderwall.com/x3ro
twitter: @x3rames