diff --git a/arduino/sketch/sketch.go b/arduino/sketch/sketch.go
index c5d8536cc42..e974d8c7bcf 100644
--- a/arduino/sketch/sketch.go
+++ b/arduino/sketch/sketch.go
@@ -115,7 +115,7 @@ func New(path *paths.Path) (*Sketch, error) {
 		// Skip files that can't be opened
 		f, err := p.Open()
 		if err != nil {
-			continue
+			return nil, err
 		}
 		f.Close()
 
@@ -166,6 +166,14 @@ func (s *Sketch) supportedFiles() (*paths.PathList, error) {
 	}
 	files.FilterOutDirs()
 	files.FilterOutHiddenFiles()
+	// Exclude files named compile_commands.json, to allow the user
+	// creating a symlink to the autogenerated file in the sketch
+	// directory, without that being handled or causing failure when
+	// the target file does not exist yet.
+	// TODO: This abuses FilterOutSuffix, it should match the
+	// filename, but go-paths-helper does not support this now.
+	files.FilterOutSuffix("compile_commands.json")
+
 	validExtensions := []string{}
 	for ext := range globals.MainFileValidExtensions {
 		validExtensions = append(validExtensions, ext)
diff --git a/go.mod b/go.mod
index 4c883effe00..d198a49d634 100644
--- a/go.mod
+++ b/go.mod
@@ -52,3 +52,5 @@ require (
 	gopkg.in/src-d/go-git.v4 v4.13.1
 	gopkg.in/yaml.v2 v2.4.0
 )
+
+replace github.com/arduino/go-paths-helper v1.6.1 => github.com/matthijskooijman/go-paths-helper v1.6.2-0.20210908151509-429170ecd10a
diff --git a/go.sum b/go.sum
index eec8bc49746..e7a72452fa5 100644
--- a/go.sum
+++ b/go.sum
@@ -255,6 +255,8 @@ github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaW
 github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
 github.com/marcinbor85/gohex v0.0.0-20210308104911-55fb1c624d84 h1:hyAgCuG5nqTMDeUD8KZs7HSPs6KprPgPP8QmGV8nyvk=
 github.com/marcinbor85/gohex v0.0.0-20210308104911-55fb1c624d84/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
+github.com/matthijskooijman/go-paths-helper v1.6.2-0.20210908151509-429170ecd10a h1:Mp/RCywh1EVgopMuG3CMjZ9S8xwLhvCZ+oDb4hLNSYY=
+github.com/matthijskooijman/go-paths-helper v1.6.2-0.20210908151509-429170ecd10a/go.mod h1:V82BWgAAp4IbmlybxQdk9Bpkz8M4Qyx+RAFKaG9NuvU=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
 github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
diff --git a/test/test_compile.py b/test/test_compile.py
index 5369a0fe185..93594c386bb 100644
--- a/test/test_compile.py
+++ b/test/test_compile.py
@@ -158,6 +158,87 @@ def test_compile_with_sketch_with_symlink_selfloop(run_command, data_dir):
     assert not result.ok
 
 
+def test_compile_with_symlink(run_command, data_dir):
+    # Init the environment explicitly
+    run_command(["core", "update-index"])
+
+    # Install Arduino AVR Boards
+    run_command(["core", "install", "arduino:avr@1.8.3"])
+
+    sketch_name = "CompileIntegrationTestSymlinkOk"
+    sketch_path = os.path.join(data_dir, sketch_name)
+    main_file = os.path.join(sketch_path, "{}.ino".format(sketch_name))
+    symlink_file = os.path.join(sketch_path, "link.ino")
+    fqbn = "arduino:avr:uno"
+
+    # Create a test sketch
+    result = run_command(["sketch", "new", sketch_path])
+    assert result.ok
+    assert "Sketch created in: {}".format(sketch_path) in result.stdout
+
+    # create a symlink to some external file and move the main .ino
+    # contents into that to check that the symlink is actually compiled
+    with tempfile.NamedTemporaryFile(delete=False) as external:
+        try:
+            os.symlink(external.name, symlink_file)
+
+            with open(main_file, mode="rb+") as main:
+                external.write(main.read())
+                external.flush()
+                main.truncate(0)
+                main.flush()
+
+            # Close to allow re-opening the file on Windows
+            # See https://bugs.python.org/issue14243
+            external.close()
+
+            # Build sketch for arduino:avr:uno
+            result = run_command(["compile", "-b", fqbn, sketch_path])
+            assert result.stderr == ""
+            assert result.ok
+        finally:
+            # Explicit cleanup needed because the file is closed above
+            os.unlink(external.name)
+
+    def test_broken_symlink(sketch_name, link_name, target_name, expect_error):
+        sketch_path = os.path.join(data_dir, sketch_name)
+        symlink_file = os.path.join(sketch_path, link_name)
+        target_file = os.path.join(sketch_path, target_name)
+        fqbn = "arduino:avr:uno"
+
+        # Create a test sketch
+        result = run_command(["sketch", "new", sketch_path])
+        assert result.ok
+        assert "Sketch created in: {}".format(sketch_path) in result.stdout
+
+        os.symlink(target_file, symlink_file)
+
+        # Build sketch for arduino:avr:uno
+        result = run_command(["compile", "-b", fqbn, sketch_path])
+
+        if expect_error:
+            expected_error = "Error during build: Can't open sketch: open {}: ".format(symlink_file)
+            assert expected_error in result.stderr
+            assert not result.ok
+        else:
+            assert result.ok
+
+    test_broken_symlink("CompileIntegrationTestSymlinkBrokenIno", "link.ino", "doesnotexist.ino", expect_error=True)
+    test_broken_symlink("CompileIntegrationTestSymlinkBrokenCpp", "link.cpp", "doesnotexist.cpp", expect_error=True)
+    test_broken_symlink("CompileIntegrationTestSymlinkBrokenH", "link.h", "doesnotexist.h", expect_error=True)
+    test_broken_symlink("CompileIntegrationTestSymlinkBrokenJson", "link.json", "doesnotexist.json", expect_error=True)
+    test_broken_symlink("CompileIntegrationTestSymlinkBrokenXXX", "link.xxx", "doesnotexist.xxx", expect_error=False)
+    # Support a usecase where a user makes a symlink to
+    # compile_commands.json in the sketch root, even when it does not
+    # exist yet/anymore
+    test_broken_symlink(
+        "CompileIntegrationTestSymlinkBrokenCompileCommands",
+        "compile_commands.json",
+        "doesnotexist.json",
+        expect_error=False,
+    )
+
+
 def test_compile_blacklisted_sketchname(run_command, data_dir):
     """
     Compile should ignore folders named `RCS`, `.git` and the likes, but