SonarCloud Scan fails to parse `.eslintcache` file

I’ve run into an issue with the SonarCloud ESLint integration while setting up SonarCloud CI analysis with GitHub workflows.

I’m getting this error when SonarCloud attempts to parse the .eslintcache file:

20:41:12.815 INFO  Importing /github/workspace/.eslintcache
20:41:12.856 WARN  No issues information will be saved as the report file can't be read.
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 100930 path $[531].messages
The complete stack trace
20:41:12.815 INFO  Importing /github/workspace/.eslintcache
20:41:12.856 WARN  No issues information will be saved as the report file can't be read.
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 100930 path $[531].messages
See https://github.com/google/gson/blob/main/Troubleshooting.md#unexpected-json-structure
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:520)
	at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
	at com.google.gson.internal.bind.ArrayTypeAdapter.read(ArrayTypeAdapter.java:76)
	at com.google.gson.Gson.fromJson(Gson.java:1361)
	at com.google.gson.Gson.fromJson(Gson.java:1262)
	at com.google.gson.Gson.fromJson(Gson.java:1199)
	at org.sonar.plugins.javascript.external.EslintReportSensor.importReport(EslintReportSensor.java:67)
	at org.sonar.plugins.javascript.external.AbstractExternalIssuesSensor.lambda$execute$1(AbstractExternalIssuesSensor.java:55)
	at java.base/java.util.ArrayList.forEach(Unknown Source)
	at org.sonar.plugins.javascript.external.AbstractExternalIssuesSensor.execute(AbstractExternalIssuesSensor.java:55)
	at org.sonar.plugins.javascript.external.EslintReportSensor.execute(EslintReportSensor.java:43)
	at org.sonar.scanner.sensor.AbstractSensorWrapper.analyse(AbstractSensorWrapper.java:63)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:75)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.lambda$execute$1(ModuleSensorsExecutor.java:48)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.withModuleStrategy(ModuleSensorsExecutor.java:66)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:48)
	at org.sonar.scanner.scan.ModuleScanContainer.doAfterStart(ModuleScanContainer.java:64)
	at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:123)
	at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:109)
	at org.sonar.scanner.scan.ProjectScanContainer.scan(ProjectScanContainer.java:192)
	at org.sonar.scanner.scan.ProjectScanContainer.scanRecursively(ProjectScanContainer.java:188)
	at org.sonar.scanner.scan.ProjectScanContainer.doAfterStart(ProjectScanContainer.java:159)
	at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:123)
	at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:109)
	at org.sonar.scanner.bootstrap.ScannerContainer.doAfterStart(ScannerContainer.java:416)
	at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:123)
	at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:109)
	at org.sonar.scanner.bootstrap.GlobalContainer.doAfterStart(GlobalContainer.java:128)
	at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:123)
	at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:109)
	at org.sonar.scanner.bootstrap.ScannerMain.runScannerEngine(ScannerMain.java:135)
	at org.sonar.scanner.bootstrap.ScannerMain.run(ScannerMain.java:52)
	at org.sonar.scanner.bootstrap.ScannerMain.main(ScannerMain.java:38)
Caused by: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 100930 path $[531].messages
See https://github.com/google/gson/blob/main/Troubleshooting.md#unexpected-json-structure
	at com.google.gson.stream.JsonReader.unexpectedTokenError(JsonReader.java:1768)
	at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:430)
	at com.google.gson.internal.bind.ArrayTypeAdapter.read(ArrayTypeAdapter.java:74)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$2.readIntoField(ReflectiveTypeAdapterFactory.java:267)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$FieldReflectionAdapter.readField(ReflectiveTypeAdapterFactory.java:558)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:516)
	... 32 common frames omitted

The complete .eslintcache file

Based on the error message, it looks like it’s having an issue with this line:

...
    "Unsafe argument of type `any` assigned to a parameter of type `DocumentNode | TypedDocumentNode<{ updateTask: { task: TaskType; errors: [{ messages: string[]; }]; }; }, OperationVariables>`.",
...

(This is the 531st instance of messages, which I believe matches path $[531].messages from the error. It is also the last instance of messages in the JSON.)

According to https://jsonlint.com/, the JSON is valid. Does anyone have an idea of what might be going wrong here, and how I might fix it?

Hello @avinoamsn,

Welcome back to the Sonar Community :slight_smile:

First, I would like to thank you for sharing not only the complete stack trace but also the input file that triggers the parsing failure. It really helped me understand the root cause.

Now, coming to the actual cause, it’s true that the contents of the .eslintcache are valid JSON. However, it does not seem to be an ESLint report that you would normally get when running eslint from the command line with the arguments -o report.json -f json.

An ESLint report normally looks like this:

[
  {
    "filePath": "/tmp/example/index.mjs",
    "messages": [
      {
        "ruleId": "no-unused-vars",
        "severity": 2,
        "message": "'x' is assigned a value but never used.",
        "line": 1,
        "column": 5,
        "nodeType": "Identifier",
        "messageId": "unusedVar",
        "endLine": 1,
        "endColumn": 6
      }
    ],
    "suppressedMessages": [],
    "errorCount": 1,
    "fatalErrorCount": 0,
    "warningCount": 0,
    "fixableErrorCount": 0,
    "fixableWarningCount": 0,
    "source": "var x = 42;;\n",
    "usedDeprecatedRules": []
  }
]

In your case, your file begins with a list of file paths, followed by data about size, time, results, hashOfConfig, and several other unrelated pieces of information that ESLint does not normally emit.

Please double-check how .eslintcache is generated and if this is really the file you intended to import, as it doesn’t include ESLint problems in JSON format.

To help you, here is a pointer to ESLint CLI Documentation.

Hope this helps,
Yassin

2 Likes

Thank you for the informative response, this resolved my issue! However, I see the root of the confusion here—

I first added the ESLint linting step to my SonarCloud Analysis workflow because I saw this message in the workflow logs:

20:09:41.152 INFO  Importing /github/workspace/.eslintcache
20:09:41.189 WARN  No issues information will be saved as the report file can't be read.
java.io.FileNotFoundException: /github/workspace/.eslintcache (No such file or directory)

Based on this message, I assumed that SonarCloud was looking for the file generated by the ESLint CLI’s --cache flag, which stores its output in a .eslintcache file by default. Had I first seen the SonarSource documentation on the subject then I might’ve avoided this confusion, but as it stands the information presented by the workflow logs appears to conflate ESLint’s --cache flag with ESLint’s --output flag.

If my understanding is correct, it might be beneficial to clarify the workflow logs to inform the user that SonarCloud is looking for output generated by ESLint’s --output flag, rather than ESLint’s --cache flag.

1 Like

Hey Avi,

That’s a fair point. I can understand why this could be misleading. However, there is one thing that I am missing.

The following log is only printed if you explicitly set the property sonar.eslint.reportPaths:

INFO  Importing /github/workspace/.eslintcache

In other words, you intentionally instructed your SonarCloud analysis to pick this particular path and import its content.

Could you clarify what made you do so?

It turns out that someone had set this value in the project settings on the SonarCloud web app. I initially didn’t define this parameter in the sonar-project.properties file, so it must’ve been reading it from there. Apologies for the confusion!

No worries :+1:

1 Like