apache / apache/fluss

Fix NoSuchElementException that occurs when recovering log segments

Open Beginner friendly
#2,943 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
2.1k
Forks
625
Avg merge
3d 14h
Merged PRs (30d)
97

Description

### Search before asking

- [x] I searched in the [issues](https://github.com/apache/fluss/issues) and found nothing similar.

### Fluss version

0.9.0 (latest release)

### Please describe the bug 🐞

When recovering log segments, invoke the readNextOffset function to calculate the offset that would be used for the next message to be appended to this segment. However, this function doesn‘t check for the scenario where batches is empty. Once batches is empty, invoking Iterables.getLast function will throw an exception.

> 2026-03-27 11:37:12,446 ERROR org.apache.fluss.server.ServerBase [] - Could not start TabletServer.
org.apache.fluss.exception.FlussException: Failed to start the TabletServer.
at org.apache.fluss.server.ServerBase.start(ServerBase.java:144) ~[fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
at org.apache.fluss.server.ServerBase.startServer(ServerBase.java:99) [fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
at org.apache.fluss.server.tablet.TabletServer.main(TabletServer.java:191) [fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
Caused by: org.apache.fluss.exception.FlussRuntimeException: Failed to recovery log
at org.apache.fluss.server.log.LogManager.loadLogs(LogManager.java:207) ~[fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
at org.apache.fluss.server.log.LogManager.startup(LogManager.java:139) ~[fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
at org.apache.fluss.server.tablet.TabletServer.startServices(TabletServer.java:228) ~[fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
at org.apache.fluss.server.ServerBase.start(ServerBase.java:131) ~[fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
... 2 more
Caused by: org.apache.fluss.exception.FlussRuntimeException: java.util.NoSuchElementException
at org.apache.fluss.server.log.LogManager$1.run(LogManager.java:518) ~[fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) ~[?:?]
at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[?:?]
at java.lang.Thread.run(Thread.java:842) ~[?:?]
Caused by: java.util.NoSuchElementException
at org.apache.fluss.utils.AbstractIterator.next(AbstractIterator.java:57) ~[fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
at org.apache.fluss.shaded.guava32.com.google.common.collect.Iterators.getLast(Iterators.java:907) ~[fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
at org.apache.fluss.shaded.guava32.com.google.common.collect.Iterables.getLast(Iterables.java:850) ~[fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
at org.apache.fluss.server.log.LogSegment.readNextOffset(LogSegment.java:414) ~[fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
at org.apache.fluss.server.log.LogLoader.recoverLog(LogLoader.java:198) ~[fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
at org.apache.fluss.server.log.LogLoader.load(LogLoader.java:93) ~[fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
at org.apache.fluss.server.log.LogTablet.create(LogTablet.java:324) ~[fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
at org.apache.fluss.server.log.LogManager.loadLog(LogManager.java:342) ~[fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
at org.apache.fluss.server.log.LogManager$1.run(LogManager.java:487) ~[fluss-server-0.9-SNAPSHOT.jar:0.9-SNAPSHOT]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) ~[?:?]
at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[?:?]

### Solution

Use Iterables.isEmpty to check if batches is empty in the readNextOffset function. If batches is empty, directly return the baseOffset.

### Are you willing to submit a PR?

- [x] I'm willing to submit a PR!

Contributor guide

No contributing guide indexed for this repository

Research direction

Start in LogSegment.readNextOffset, then trace its use from LogLoader.recoverLog during log recovery. Reproduce or test recovery with an empty batches collection and verify that recovery completes without NoSuchElementException and uses the segment's baseOffset.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend, distributed-systems
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
82/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.