Wednesday, February 15, 2023

AWS SAM CLI FileNotFoundError: WinError 3: The system cannot find the path specified .class class Kotlin 1.7 Windows 10

Introduction

The AWS SAM CLI command 

sam.cmd build MyFunction --template C:\techie\workspace\my-function\local\template.yaml --build-dir C:\techie\workspace\my-function\local\.aws-sam\build --debug 

fails in an IntelliJ commandline terminal due to this 

FileNotFoundError: [WinError 3] The system cannot find the path specified 

error.



Setup

- Windows 10 Pro laptop

- IntelliJ 2022

- Kotlin 1.7

- Java 11 at least for compilation

- Serverless lambda written in Kotlin

- AWS SAM CLI, version 1.67.0

- AWS Toolkit plugin for IntelliJ 

Investigation

First I tried to install SAM AWS CLI using HomeBrew (formerly Brew) in WSL 1 (ubuntu) under Windows 10 using these steps: 

https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-homebrew.html

But that failed during Homebrew installation. Probably upgrading to WSL 2 would fix that. But then I also realized: IntelliJ then doesn't know about that at all, since SAM CLI is then installed in WSL, not in Windows.

It kept on saying after running brew postinstall --verbose --debug gcc

==> Installing aws-sam-cli from aws/tap

Error: An exception occurred within a child process:

  Errno::EFAULT: Bad address - /home/linuxbrew/.linuxbrew/bin/gcc-12

And also:

Warning: The post-install step did not complete successfully

You can try again using:

  brew postinstall gcc

Also trying brew postinstall --verbose --debug gcc didn't succeed.  This error mentioned here was also applicable: https://github.com/orgs/Homebrew/discussions/4052

I also didn't dare wsl --update because other configurations I already had set up might fail after that. Guess I will do that at a more quiet moment :)

So then I went for the manual installation in Windows, as found here: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html

In IntelliJ you then have to set the path to the executable to where you installed it:


So IntelliJ will use the Windows AWS SAM CLI, not the one in the terminal (WSL 1).

Than I ran my command, first outside IntelliJ to be able to control the parameters more easily:

C:\Users\techie>C:\Amazon\AWSSAMCLI\bin\sam.cmd build MyFunction --template C:\techie\workspace\my-function\local\template.yaml --build-dir C:\techie\workspace\my-function\local\.aws-sam\build --debug

But that gave this error:

FileNotFoundError: [WinError 3] The system cannot find the path specified: 'C:\\Users\\techie\\AppData\\Local\\Temp\\tmpmjdhug40\\7c98ad184709dded6b1c874ece2a0edea9c55b0a\\build\\classes\\kotlin\\test\\com\\mycompany\\myfunction\\domain\\MyServiceTest$should register valid make this a long text to exceed this successfully$2.class'

First I thought it was due to spaces in the test-methodname. But replacing them with an underscore didn't work either. Or maybe case-insensitive-ness; but my test-methodname is all lowercase.

I tried many things to exclude the whole test-class from the process, because why is it even included during the sam build command? 

Options I tried were:

  1. Setting GRADLE_OPTS before running the command -x test, similar to the MAVEN_OPTS example here: https://github.com/aws/aws-sam-cli/issues/1105#issuecomment-777703158
  2. Excluding the test-file or even just all tests in build.gradle, like:

    jar {

      sourceSets {

            main {

                java {

                    exclude '**/TestExcludeClass.java'

                }


                kotlin {

                    exclude '**/TestExcludeKotlinClass.kt'

                }

            }

        }

    }

    Note that excluding everything with 'exclude '**/*.kt'  did make the sam build fail, so the changes were taken into account.
  3. In build.gradle add: excludeTestsMatching "com.mycompany.myfunction.lambda.MyServiceTest"
  4. test.onlyIf { ! Boolean.getBoolean(skipTests) } and then specifying as GRADLE_OPTS="-DskipTests=true"

It seems the initial step of the sam build (JavaGradleWorkflow:JavaGradleCopyArtifacts) just takes all .class files anyway, even test classes.

I tried turning off Telemetry That did have no affect on the error.

Solution

Then I found this comment: https://github.com/aws/aws-sam-cli/issues/4031#issuecomment-1173730737

Could it be that, that the path is just too long? Typical Windows limit so that could definitely be it.

And yes after applying below command in PowerShell as an Administrator

New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" `-Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force

it worked!

Detailed explanation: https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=powershell#enable-long-paths-in-windows-10-version-1607-and-later

The command ran fine! This is then the output:

Build Succeeded

Built Artifacts  : ..\..\techie\workspace\my-function\local\.aws-sam\build

Built Template   : ..\..\techie\workspace\my-function\local\.aws-sam\build\template.yaml

Commands you can use next

=========================

[*] Validate SAM template: sam validate

[*] Invoke Function: sam local invoke -t ..\..\techie\workspace\my-function\local\.aws-sam\build\template.yaml

[*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch

[*] Deploy: sam deploy --guided --template-file ..\..\techie\workspace\my-function\local\.aws-sam\build\template.yaml