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.
ls -la ~/languages/
- drwxr-xr-x
- ▶ PHP
- ▶ Ruby
- ▶ Scala
- ▶ C#
- ▶ JavaScript
- ▶ Objective-C
- ▶ Shell Scripting
ls -la ~/toolchain/
- drwxr-xr-x
- ▶ Typo3
- ▶ Akka
- ▶ Capistrano
- ▶ Git
- ▶ MAMP
- ▶ Adobe Illustrator
- ▶ NSTrackingArea (Cocoa)
uname -a
- drwxr-xr-x
- ▶ Mac OS X
- ▶ Unix
Understanding and fixing Scala Akka dead letters warnings
Akka dead letters warnings can look alarming because they often appear in large groups, with messages such as Message [X] from Actor[...] to Actor[...] was not delivered. In many systems, this is a normal signal that an actor has stopped, restarted, or no longer has a recipient. In others, it reveals lost work, a shutdown race, or a mailbox that has become unusable.
The important detail is that a dead letter is a message that reached the actor system’s event stream but could not be delivered to its intended actor. The warning describes the delivery result, not necessarily the original failure. Finding the underlying cause means checking actor lifecycle events, supervision, mailbox state, recipient paths, and application shutdown behaviour together.
This matters in practical Scala services running across Australian cloud regions and local development machines. A team in Sydney may see warnings during an overnight deployment, while a Melbourne developer sees the same messages after stopping an IntelliJ run configuration. Time-zone differences, container restarts, and production traffic patterns can make an intermittent actor problem appear much harder to reproduce.
What a dead letter actually means
Akka actors communicate by sending immutable messages to an ActorRef. If the destination has been terminated, the reference points to an invalid path, the system is shutting down, or the message is rejected by a mailbox, Akka publishes the message as a dead letter. The default logging configuration usually turns some of these events into warnings.
A dead letter does not automatically mean that an exception occurred inside the receiving actor. For example, sending a message to context.parent after the parent has stopped can produce a dead letter even though the sender itself is healthy. Likewise, a scheduled tick can arrive after an actor has completed its work and been terminated.
Actor paths are a frequent source of confusion. A path such as /user/orders is different from /system/orders, and a remote actor path contains address information that must match the active provider and configuration. Code that reconstructs a path as a string is more fragile than code that retains and passes the original ActorRef.
The common causes behind repeated warnings
The most common cause is a lifecycle race. An actor sends a final response, acknowledgement, or cleanup message while the recipient is stopping. This often appears during application shutdown, rolling deployments, or test teardown. A PoisonPill, stop, or supervision decision can terminate an actor while other components still hold its reference.
A second cause is an actor that has been restarted after failure. Depending on the design, messages sent to an old child, temporary actor, or stale route may no longer reach the intended processing path. In clustered applications, a node leaving the cluster can make remote references invalid until routing and membership information settle.
Mailbox problems deserve separate attention. An unbounded mailbox can grow until memory pressure destabilises the process, while a bounded mailbox can reject messages once its capacity is reached. If an actor is blocked by slow I/O, synchronous calls, or excessive CPU work, messages may appear to be lost even though the initial problem is a stalled consumer. The stalled mailbox guide provides a useful diagnostic path for that specific pattern.
A practical way to investigate the source
Start by capturing the complete warning, including the message class, sender, recipient path, and timestamp. A line saying DeadLetterSuppression or showing an ordinary system message may be harmless, while a business command such as ProcessPayment or ReserveStock requires a much more serious review.
Then correlate the warning with actor lifecycle and application logs. Look for Terminated, supervision failures, restart messages, cluster membership changes, deployment events, and JVM shutdown notices. Include a correlation ID in important messages so that a dead letter can be traced back to an HTTP request, queue record, or scheduled job.
Useful evidence can be organised like this:
| Evidence | What it can indicate | Practical response |
|---|---|---|
| Many warnings during shutdown | Expected messages arriving after termination | Review shutdown ordering and reduce log noise |
| Business commands becoming dead letters | Work may have been dropped | Add acknowledgement, retry, or durable hand-off |
| Warnings after actor restart | Stale references or incorrect supervision design | Reacquire the child reference and inspect restart semantics |
| Warnings with mailbox errors | Consumer blockage or capacity exhaustion | Profile the actor and review mailbox configuration |
| Remote paths failing after node changes | Cluster or transport instability | Check provider, address, membership, and deployment settings |
Reproduce the issue with a small test rather than beginning with production logging changes. Stop the recipient immediately before sending a message, restart the child during processing, and terminate the actor system while scheduled tasks are active. Deterministic tests expose ordering assumptions that can remain hidden in a busy production service.
Local tooling can also affect what developers observe. A Mac-based Scala project may behave differently when a run is stopped from the IDE compared with a clean application shutdown; the author’s Mac OS X notes can help when checking platform-specific development setup and process behaviour.
Fixing delivery, shutdown, and mailbox design
The safest fix is usually architectural: give important work a durable boundary. If losing a message would lose an order, payment, or customer action, do not rely on an in-memory actor mailbox as the only copy. Persist it in a database or durable queue, then let an actor process it with an explicit acknowledgement and retry policy.
For ordinary actor-to-actor communication, keep references stable and make ownership clear. Create children through the intended parent, pass the resulting ActorRef, and avoid constructing actor paths manually. Use watch or watchWith when a component needs to respond to termination, and ensure that a sender has a defined policy for Terminated rather than continuing to send blindly.
Shutdown needs an ordered protocol. Stop accepting new work, tell coordinators to drain, wait for acknowledgements or a deadline, and only then terminate workers and the actor system. Scheduled messages should be cancelled where appropriate. In an Akka HTTP service, coordinate server termination with actor termination so requests are not accepted after their processing actors have disappeared.
For mailbox and throughput issues, remove blocking operations from actor execution where possible. Move slow database or network work to an appropriate execution context, set realistic mailbox limits, and monitor processing time. A larger mailbox may postpone failure without solving the bottleneck. Back-pressure, bounded concurrency, and explicit rejection are usually clearer than silently accumulating messages.
Reducing noise without hiding failures
Some dead letters are expected. Akka can emit them when an application shuts down, when temporary actors finish, or when a test intentionally sends to a terminated recipient. Configure dead-letter subscriptions and logging carefully so routine events do not bury meaningful failures, but avoid globally suppressing all dead-letter output.
A useful approach is to classify messages. System-level termination notices can be logged at a lower level, while business messages should remain visible and trigger metrics. Count dead letters by message type, recipient path, and environment. A sudden increase in a Brisbane deployment should be distinguishable from the normal burst produced by a nightly restart.
Operational context matters in Australia. A service serving customers in Sydney, Perth, and Melbourne may have traffic peaks that do not align neatly with a single local clock, and daylight-saving changes affect some states but not others. Record timestamps in UTC, retain deployment identifiers, and compare warnings with container and load-balancer events rather than relying on a developer’s wall clock.
Privacy obligations also shape diagnostics. Under Australia’s Privacy Act, logs should not casually contain personal information, payment details, or full request payloads. Use message type names, hashed identifiers, correlation IDs, and carefully selected metadata. This provides enough evidence to trace delivery failures without turning debug logging into an unnecessary data-retention risk.
When warnings point to real lost work, fix the delivery guarantee rather than merely adjusting the logger. Add tests for shutdown races, actor restarts, bounded mailboxes, and remote node loss. Review the warning after deployment, confirm that expected shutdown noise has reduced, and verify that important commands still receive a response or reach a durable retry path.
Treat each warning as evidence about actor lifecycle and message ownership. Trace the recipient, reproduce the ordering, choose an appropriate delivery guarantee, and make shutdown behaviour explicit. With those steps in place, dead letters become a useful diagnostic signal instead of an endless stream of mysterious Akka warnings.
cat ~/interests.json
| Key | Value |
|---|---|
| editor | Terminal-first workflow |
| os | Mac OS X / Unix |
| vcs | Git, distributed version control |
| deploy | Capistrano, cron automation |
| graphics | SVG, Adobe Illustrator troubleshooting |
| networking | IP validation, SSH, VPN |
git log --oneline --reverse
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.
Solving NDK build issues on OS X
Troubleshooting native development kit compilation problems on Mac OS X.
Programmatically adding PHP generated TypoScript to the backend configuration
Integrating dynamically generated TypoScript into Typo3 backend setups using PHP.
ArgumentError: Could not parse PKey: no start line
Debugging an SSH key parsing error encountered during deployment.
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.
Cocoa: Using NSTrackingArea
A short tutorial on using Cocoa's NSTrackingArea to capture mouseEntered and mouseExited events.
cat ~/contact.txt