typelevel / typelevel/fs2

`fs2.io.Watcher#watch` with a relative path to file causes an NPE

Open
#3,472 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Scala
Stars
2.5k
Forks
636
Avg merge
2d 4h
Merged PRs (30d)
7

Description

It seems that supplying a relative java.nio.file.Path to the watcher's fs2.io.Watcher#watch method causes an NPE:

import fs2.io.Watcher
import fs2.io.file.{Files, Path}
import cats.effect.*
import cats.effect.unsafe.implicits.global

@main def main = {

    java.nio.file.Files.createDirectories(java.nio.file.Path.of("foo"))

    val f = java.nio.file.Path.of("a.json")
    if (!java.nio.file.Files.exists(f)) {
        java.nio.file.Files.createFile(f)
    }

    println(f)
    Watcher
        .default[IO].use{ w => w.watch(f) }
        .unsafeRunSync()
}
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.nio.file.Path.register(java.nio.file.WatchService, java.nio.file.WatchEvent$Kind[], java.nio.file.WatchEvent$Modifier[])" because "path$7" is null
	at fs2.io.Watcher$DefaultWatcher.registerUntracked$$anonfun$1(DeprecatedWatcher.scala:301)
	at blocking @ fs2.io.Watcher$.default(DeprecatedWatcher.scala:153)
	at flatMap @ fs2.io.Watcher$DefaultWatcher.watchFile(DeprecatedWatcher.scala:278)
	at blocking @ fs2.io.Watcher$.default(DeprecatedWatcher.scala:153)
	at flatMap @ fs2.io.Watcher$DefaultWatcher.watch(DeprecatedWatcher.scala:212)
	at of @ fs2.io.Watcher$.fromWatchService(DeprecatedWatcher.scala:180)
	at map @ fs2.io.Watcher$.fromWatchService(DeprecatedWatcher.scala:181)
	at map @ fs2.io.Watcher$.fromFileSystem$$anonfun$2(DeprecatedWatcher.scala:161)
	at blocking @ fs2.io.Watcher$.default(DeprecatedWatcher.scala:153)
	at flatMap @ fs2.io.Watcher$.fromFileSystem(DeprecatedWatcher.scala:161)
	at apply @ fs2.io.Watcher$.fromFileSystem(DeprecatedWatcher.scala:162)

At some point getParent was called on the path parameter:

https://github.com/typelevel/fs2/blob/1e4d752c1301df7e4005fdb5d6d84787e15d1ea3/io/jvm-native/src/main/scala/fs2/io/DeprecatedWatcher.scala#L266

If we resolve the path (e.g call toAbsolutePath) the issues goes away and the watcher works as expected.
Happy to add test and fix in a PR if confirmed.

fs2-io version: 3.11.0
Scastie: https://scastie.scala-lang.org/BoemfzqmQh2HAlRCeGnEbA

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in io/jvm-native/src/main/scala/fs2/io/DeprecatedWatcher.scala around line 266, following Watcher.default and the watch entry point where getParent is used. Reproduce the example with a relative file path, then verify that the watcher no longer throws an NPE and observes the expected file events.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, scala
Domain
operating-systems
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.