amplify-backend icon indicating copy to clipboard operation
amplify-backend copied to clipboard

Amplify deploy fails when using function resolver with env by TypeScript error

Open mm-k-takashima opened this issue 1 year ago • 14 comments
trafficstars

Environment information

System:
  OS: Windows 11 10.0.22631
  CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
  Memory: 4.69 GB / 15.79 GB
Binaries:
  Node: 20.12.0 - ~\AppData\Local\Volta\tools\image\node\20.12.0\node.EXE
  Yarn: undefined - undefined
  npm: 10.5.0 - ~\AppData\Local\Volta\tools\image\npm\10.5.0\bin\npm.CMD
  pnpm: undefined - undefined
NPM Packages:
  @aws-amplify/backend: 0.13.2
  @aws-amplify/backend-cli: 0.13.0
  aws-amplify: 6.0.30
  aws-cdk: Not Found
  aws-cdk-lib: 2.138.0
  typescript: 5.4.5
AWS environment variables:
  AWS_NODEJS_CONNECTION_REUSE_ENABLED = 1
  AWS_SDK_LOAD_CONFIG = 1
  AWS_STS_REGIONAL_ENDPOINTS = regional
No CDK environment variables

Description

Code

Structure
amplify
├───data
│       └───resource.ts
└───functions
         └───function-with-env
                      ├───handler.ts
                      └───resource.ts
Implementations
  • amplify/functions/function-with-env/handler.ts
// ...

// Ref. https://docs.amplify.aws/gen2/build-a-backend/functions/#accessing-environment-variables 
/* @ts-noncheck directive for first 'amplify sandbox' run to avoid non-existence */
import { env } from '$amplify/env/function-with-env';

// ...
type FunctionWithEnvHandler = Schema['<query>']['functionHandler'];

export const handler: FunctionWithEnvHandler = async () => {
  const apiHost = env['API_HOST'];
  const apiKey = env['API_KEY'];

  // ... list items from outside service and resolve types ...
  
  return customTypeArray; 
}

  • amplify/functions/function-with-env/resource.ts
import { defineFunction, secret } from '@aws-amplify/backend';

const apiHost = process.env.API_HOST as string;
const apiKey = secret('API_KEY');

const environment = {
  API_HOST: apiHost,
  API_KEY: apiKey,
};

export const functionWithEnv= defineFunction({
  environment,
  timeoutSeconds: 10,
});

  • amplify/data/resource.ts
import { functionWithEnv } from '../functions/function-with-env/resource';
// ...

const schemaopt = {
  <custom-type>: a
    .customType({
      // typedef
    }),
  <query>: a
    .query()
    .returns(a.ref('<custom-type>').array())
    .handler([a.handler.function(functionWithEnv)])
    .authorization((auth) => [auth.guest(), auth.authenticated()]),
};
const schemaImpl = a.schema(schemaopt);
export type Schema = ClientSchema<typeof schemaImpl>;

export const data = defineData({
  schema: schemaImpl,
  authorizationModes: {
    defaultAuthorizationMode: 'userPool',
  },
});
// ...
Others
  • .amplify/generated/env/function-with-env.ts (git ignored)
// This file is auto-generated by Amplify. Edits will be overwritten.
export const env = process.env as LambdaProvidedEnvVars & AmplifyBackendEnvVars;

/** Lambda runtime environment variables, see https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-runtime */
type LambdaProvidedEnvVars = {
  // ... auto generated settings ...
};

/** Amplify backend environment variables available at runtime, this includes environment variables defined in `defineFunction` and by cross resource mechanisms */
type AmplifyBackendEnvVars = {
  API_HOST: string;
  API_KEY: string;
};
  • amplify/tsconfig.json
{
  "compilerOptions": {
    "target": "es2022",
    "module": "es2022",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true,
    "paths": {
      "$amplify/*": ["../.amplify/generated/*"]
    }
  }
}

Error detail

Sandbox deploy is succeeded. But deploy on Amplify CI/CD is failed.

Deploy log
2024-04-24T10:07:52.788Z [INFO]: # Executing command: npx amplify pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID
2024-04-24T10:07:59.702Z [INFO]:
2024-04-24T10:08:05.537Z [INFO]: amplify/functions/<function-with-env>/handler.ts(4,21): error TS2307: Cannot find module '$amplify/env/<function-with-env>' or its corresponding type declarations.
2024-04-24T10:08:05.573Z [INFO]:
2024-04-24T10:08:05.573Z [WARNING]: amplify pipeline-deploy
Command to deploy backends in a custom CI/CD pipeline. This command is not intended to be used locally.

[...]

2024-04-24T10:08:05.574Z [INFO]: SyntaxError: TypeScript validation check failed.
Resolution: Fix the syntax and type errors in your backend definition.
Cause:
2024-04-24T10:08:05.634Z [ERROR]: !!! Build failed
2024-04-24T10:08:05.634Z [INFO]: Please read more about Amplify Hosting's support for SSR frameworks to find if your build failure is related to an unsupported feature: https://docs.aws.amazon.com/amplify/latest/userguide/amplify-ssr-framework-support.html. You may also find this troubleshooting guide useful: https://docs.aws.amazon.com/amplify/latest/userguide/troubleshooting-ssr-deployment.html
2024-04-24T10:08:05.634Z [ERROR]: !!! Error: Command failed with exit code 1

Expected

I want to meet these usecases.

  • Success 'npx amplify sandbox' (generated env is existing)
  • Success 'npx amplify sandbox' (generated env is not existing / first execution)
  • Success Amplify CI/CD

What method should I take?(How to avoid TS check, wait for fix, or else ...)

mm-k-takashima avatar Apr 25 '24 05:04 mm-k-takashima

Hey @mm-k-takashima, thank you for reaching out. I was able to reproduce the issue. Marking as bug for further investigation.

ykethan avatar Apr 25 '24 16:04 ykethan

@mm-k-takashima on the local sandbox could you remove the .amplify/generated folder and restart the sandbox? this should regenerate the env files. Could you let us know if sandbox throws Cannot find module '$amplify/env/<function-with-env>' error.

ykethan avatar Apr 25 '24 17:04 ykethan

@ykethan

I tried it.

  • amplify/functions/function-with-env/handler.ts
// remove @ts-noncheck directive
import { env } from '$amplify/env/function-with-env';
### delete .amplify/generated/env and check it.

$ > npx tsc
$ > amplify/functions/<function-with-env>/handler.ts:4:21 - error TS2307: Cannot find module '$amplify/env/<function-with-env>' or its corresponding type declarations.

$ > 4 import { env } from '$amplify/env/<function-with-env>';

Found 1 error in amplify/functions/<function-with-env>/handler.ts:4

### restart sandbox

$ > aws sso login --profile project-x-profile

### sso login logs ... ###

$ > npx amplify sandbox --profile project-x-profile

### stack creation logs ... ###

$ > [Sandbox] Detected file changes while previous deployment was in progress. Invoking 'sandbox' again
File written: amplifyconfiguration.json

And I confirmed .amplify/generated/env/function-with-env.ts generation has been succeeded.

// This file is auto-generated by Amplify. Edits will be overwritten.
export const env = process.env as LambdaProvidedEnvVars & AmplifyBackendEnvVars;

/** Lambda runtime environment variables, see https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-runtime */
type LambdaProvidedEnvVars = {
/** The handler location configured on the function. */
_HANDLER: string;

/** The X-Ray tracing header. This environment variable changes with each invocation. */
_X_AMZN_TRACE_ID: string;

/** The default AWS Region where the Lambda function is executed. */
AWS_DEFAULT_REGION: string;

/** The AWS Region where the Lambda function is executed. If defined, this value overrides the AWS_DEFAULT_REGION. */
AWS_REGION: string;

/** The runtime identifier, prefixed by AWS_Lambda_ (for example, AWS_Lambda_java8). */
AWS_EXECUTION_ENV: string;

/** The name of the function. */
AWS_LAMBDA_FUNCTION_NAME: string;

/** The amount of memory available to the function in MB. */
AWS_LAMBDA_FUNCTION_MEMORY_SIZE: string;

/** The version of the function being executed. */
AWS_LAMBDA_FUNCTION_VERSION: string;

/** The initialization type of the function, which is on-demand, provisioned-concurrency, or snap-start. */
AWS_LAMBDA_INITIALIZATION_TYPE: string;

/** The name of the Amazon CloudWatch Logs group for the function. */
AWS_LAMBDA_LOG_GROUP_NAME: string;

/** The name of the Amazon CloudWatch Logs stream for the function. */
AWS_LAMBDA_LOG_STREAM_NAME: string;

/** AWS access key. */
AWS_ACCESS_KEY: string;

/** AWS access key ID. */
AWS_ACCESS_KEY_ID: string;

/** AWS secret access key. */
AWS_SECRET_ACCESS_KEY: string;

/** AWS Session token. */
AWS_SESSION_TOKEN: string;

/** The host and port of the runtime API. */
AWS_LAMBDA_RUNTIME_API: string;

/** The path to your Lambda function code. */
LAMBDA_TASK_ROOT: string;

/** The path to runtime libraries. */
LAMBDA_RUNTIME_DIR: string;

/** The locale of the runtime. */
LANG: string;

/** The execution path. */
PATH: string;

/** The system library path. */
LD_LIBRARY_PATH: string;

/** The Node.js library path. */
NODE_PATH: string;

/** For X-Ray tracing, Lambda sets this to LOG_ERROR to avoid throwing runtime errors from the X-Ray SDK. */
AWS_XRAY_CONTEXT_MISSING: string;

/** For X-Ray tracing, the IP address and port of the X-Ray daemon. */
AWS_XRAY_DAEMON_ADDRESS: string;

/** The environment's time zone. */
TZ: string;

};

/** Amplify backend environment variables available at runtime, this includes environment variables defined in `defineFunction` and by cross resource mechanisms */
type AmplifyBackendEnvVars = {
API_HOST: string;
API_KEY: string;
};

But deploy fails because of TS2307 . image

mm-k-takashima avatar Apr 26 '24 01:04 mm-k-takashima

Hey @mm-k-takashima, apologies for the delay. Wasn't able to reproduce the issue. Could you provide us your amplify.yml script present on the Amplify console -> build settings It would be great if you provide us reproduction steps or a Github repository with minimal reproduction to dive deeper into the issue.

ykethan avatar Apr 30 '24 14:04 ykethan

@ykethan Thank you for your reasearch. My amplify.yml is below.

version: 1
backend:
  phases:
    build:
      commands:
        - echo "API_HOST=$API_HOST" >> amplify/.env # Tried to create an adapter class for backend environment variable.
        - npm ci
        - npx amplify pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID
frontend:
  phases:
    preBuild:
      commands:
        - npm ci
    build:
      commands:
        - npm run build
  artifacts:
    baseDirectory: .next
    files:
      - '**/*'
  cache:
    paths:
      - .next/cache/**/*
      - node_modules/**/*

As an additional context, I am using Next.js. This may be affecting this. Below are the files that may be relevant.

  • /tsconfig.json
{
  "compilerOptions": {
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./app/*"],
      "@@/*": ["./*"],
      "$amplify/*": ["./.amplify/generated/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}
  • next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true
};

export default nextConfig;
  • package.json
{
  "name": "amplify-testing-geo",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "test": "vitest --passWithNoTests",
    "lint": "next lint",
    "format": "prettier --write --ignore-path .gitignore './**/*.{js,jsx,ts,tsx,json,css}' && next lint --fix"
  },
  "volta": {
    "node": "20.12.0",
    "npm": "10.5.0"
  },
  "dependencies": {
    "@aws-amplify/geo": "^3.0.27",
    "@aws-amplify/ui-react": "^6.1.8",
    "@aws-amplify/ui-react-geo": "^2.0.13",
    "aws-amplify": "^6.0.28",
    "dotenv": "^16.4.5",
    "next": "14.1.4",
    "prism-react-renderer": "^2.3.1",
    "react": "^18.2.0",
    "react-code-block": "^1.0.0",
    "react-dom": "^18.2.0",
    "react-icons": "^5.1.0"
  },
  "devDependencies": {
    "@aws-amplify/backend": "^0.13.0",
    "@aws-amplify/backend-cli": "^0.13.0",
    "@testing-library/react": "^14.3.1",
    "@types/node": "^20.12.7",
    "@types/react": "^18.2.79",
    "@types/react-dom": "^18.2.25",
    "@typescript-eslint/eslint-plugin": "^6.21.0",
    "@vitejs/plugin-react": "^4.2.1",
    "aws-cdk-lib": "^2.138.0",
    "constructs": "^10.3.0",
    "esbuild": "^0.20.2",
    "eslint": "^8.57.0",
    "eslint-config-next": "14.1.4",
    "eslint-config-prettier": "^9.1.0",
    "jsdom": "^24.0.0",
    "lefthook": "^1.6.10",
    "prettier": "^3.2.5",
    "tsx": "^4.7.2",
    "typescript": "^5.4.5",
    "vitest": "^1.5.0"
  }
}

It would be great if you provide us reproduction steps or a Github repository with minimal reproduction to dive deeper into the issue.

Sorry, this cannot be done immediately. Could you please wait a week or so?

mm-k-takashima avatar May 01 '24 07:05 mm-k-takashima

Hey sure, do add a reply on this thread. would be happy in diving into this.

ykethan avatar May 02 '24 16:05 ykethan

I have Similar errors.

./amplify/data/deletePostHandler/handler.ts:4:21
Type error: Cannot find module '$amplify/env/CommunityBoardDeletePost' or its corresponding type declarations.

  2 | import { Amplify } from "aws-amplify";
  3 | import { generateClient } from "aws-amplify/data";
> 4 | import { env } from "$amplify/env/CommunityBoardDeletePost";
    |                     ^
  5 |
  6 | const modelIntrospection = {
  7 |   version: 1,

tsconfig settings and env file generation have completed successfully. However, an error occurs when building next.js.

rnrnstar2 avatar May 09 '24 08:05 rnrnstar2

In addition to tsconfig.json in the amplify directory, the problem was resolved by setting the following settings as the paths of tsconfig.json directly under the next.js project.

$amplify/*": ["./.amplify/generated/*"]

But doing so will result in a new type error.

Conversion from type 'ProcessEnv' to type 'LambdaProvidedEnvVars & AmplifyBackendEnvVars' may be wrong as they cannot overlap sufficiently with each other. If you do this intentionally, convert the expression to 'unknown' first.
   Type 'ProcessEnv' is missing the following properties from type 'LambdaProvidedEnvVars': _HANDLER, _X_AMZN_TRACE_ID, AWS_DEFAULT_REGION, AWS_REGION, 20, etc. ts(2352)

This can be resolved by manually setting unknown, but it takes time. Is there any solution?

rnrnstar2 avatar May 09 '24 10:05 rnrnstar2

@ykethan I apologies for the delay of reply. Since Amplify became GA, I was trying to see if the same problem occurs with the new version(@aws-amplify/backend: 1.0.0). https://github.com/aws-amplify/amplify-backend/issues/1374#issuecomment-2090889848

As it turns out, the first problem shown Cannot find module '$amplify/env/<function-with-env>' no longer occurs. I don't know what caused the problem. But since the issue has been resolved, I think that this issue can be closed.

However, instead of the first problem being resolved, I now have a problem regarding ProcessEnv as indicated by @rnrnstar2 in the file: $amplify/generated/env/function-name.ts .

 Type 'ProcessEnv' is missing the following properties from type 'LambdaProvidedEnvVars': _HANDLER, _X_AMZN_TRACE_ID, AWS_DEFAULT_REGION, AWS_REGION, 20, etc. ts(2352)

Should we create another assignment on this issue or should we continue in this thread?

mm-k-takashima avatar May 14 '24 06:05 mm-k-takashima

Hey @rnrnstar2 @mm-k-takashima, did run a similar error recently on the frontend build with nextjs

2024-05-14T17:03:29.973Z [WARNING]: Failed to compile.

2024-05-14T17:03:29.977Z [WARNING]: ./amplify/function/handler.ts:1:21

Type error: Cannot find module '$amplify/env/say-hello' or its corresponding type declarations.

adding a exclude with "exclude": ["node_modules","amplify/**/*"] on the root tsconfig seems to have mitigated the error on the frontend build. instead of the paths could you try setting the exclude and let us know if this mitigates the issue.

ykethan avatar May 14 '24 17:05 ykethan

@ykethan I added "exclude": ["node_modules", ".amplify", "./amplify"] to the root tsconfig, and resolved the problem. A lot of thanks for your support!

mm-k-takashima avatar May 16 '24 07:05 mm-k-takashima

@mm-k-takashima thank you for the confirmation. Marking this as documentation, to add this information to the troubleshooting document.

ykethan avatar May 16 '24 14:05 ykethan

I'm running into the same issue with a Vue + Vite project, and neither adding the exclude nor adding to the path seemed to fix it. The only workaround I have is to add .amplify directory to include in tsconfig.app.json, but even then the shorthand $amplify won't work, even after adding it to path

(for clarification's sake, here's my tsconfig.app.json)

{
  "extends": "@vue/tsconfig/tsconfig.dom.json",
  "include": ["env.d.ts", "src/**/*", "src/**/*.vue", "amplify/**/*", ".amplify/generated/**/*"],
  "exclude": ["src/**/__tests__/*"],
  "compilerOptions": {
    "composite": true,
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",

    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "$amplify/*": [
        "../.amplify/generated/*"
      ]
    }
  }
}

Happy to give whatever other info can be helpful

MichaelJBerk avatar May 20 '24 18:05 MichaelJBerk

Hey folks :wave: there are a few default tsconfig configurations that appear to be picking up the generated files from Amplify. We'll work towards documenting this soon, and maybe a message/codemod to help avoid this, but in the meantime you should be able to exclude the amplify and .amplify directories in your tsconfig

{
  "exclude": ["amplify/**/*", ".amplify/**/*"]
}

Amplify will perform type-checking on sandbox and pipeline-deploy using the tsconfig local to the amplify backend (amplify/tsconfig.json). If you'd like to extend your base configuration you can add it to the localized tsconfig.

Alternatively, if you work within a monorepo you can move your backend to its own package and export the Schema and outputs for ease of sharing with your other apps. For example, in your backend package's package.json

{
  "name": "my-backend",
  "private": true,
  "exports": {
    "./schema": "./amplify/data/resource.ts",
    "./outputs": "./amplify_outputs.json"
  }
}

josefaidt avatar May 22 '24 17:05 josefaidt

Just letting you all know, I had this exact problem, excluding the files solved it immediately. I suppose it's already on the works but changing the cli tool for the init to modify the tsconfig.json file to add those lines might be a very good Idea.

I'm thankful I found this. Good luck everyone.

crafael23 avatar May 25 '24 05:05 crafael23

I seem to still be having the issue even when excluding it.

It works with my sandbox but as soon as I push it to github and the build starts, I get this:

Screenshot 2024-05-28 at 5 19 22 PM

This is going to sound crazy and I don't know why it is but this only happened when I renamed a folder to an uppercase letter instead of a lowercase letter. I reverted my commit back and forth to see. That is literally the only difference. Is there maybe something that gets cached when this runs?

npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID

LukaASoban avatar May 28 '24 21:05 LukaASoban

Hi Team,

Just to let you know,

I'm facing the same issue by using the quickstart template for React on the Gen 2 Documentation.

-> Following this part of the documentation and trying to push to prod it still throws the following error "2024-06-05T05:34:30.549Z [INFO]: amplify/backend.ts(4,26): error TS2307: Cannot find module './functions/say-hello/resource' or its corresponding type declarations."

I've already to add the exclude line on the root config file and it still throws the same build error.

Attached my tsconfig root file

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src"],
  "exclude": ["node_modules", ".amplify", "./amplify","amplify/**/*", ".amplify/**/*"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

If there have been any updates or maybe an advice it would be great!

Thank you :D

cotaloractg avatar Jun 05 '24 05:06 cotaloractg

Screenshot 2024-06-10 at 10 33 01 PM

having the same issue here :/

mikesosa avatar Jun 11 '24 03:06 mikesosa

image

Same issue for me... Exclusions don't seem to be working... Any news on this?

CBougoZ avatar Jun 13 '24 20:06 CBougoZ

Hey @CBougoZ is your function named custom-authorizer? can you share the defineFunction definition?

josefaidt avatar Jun 13 '24 21:06 josefaidt

Hi @josefaidt,

image

Please, tell me that I am missing something obvious...

CBougoZ avatar Jun 13 '24 22:06 CBougoZ

@CBougoZ the generated env file name is based on the Function name, which if not specified falls back to the directory name. Can you specify name: "custom-authorizer"? With the current setup I believe the generated file name is $amplify/env/data (this gets generated to .amplify/generated/env/data.ts)

josefaidt avatar Jun 13 '24 22:06 josefaidt

@josefaidt First of all thanks for your support. Yesterday it was getting late (I am located in Greece), so I had to go to bed. Unfortunately, what you suggested didn't do the trick. I moved the custom-authorizer.ts into a separate amplify/functions/custom-authorizer/handler.ts file. I also moved the defineFunction invocation from amplify/data/resoure.ts into amplify/functions/custom-authorizer/resource.ts file. So that basically meant that the defaults were used. Now it is working. I don't know why it wasn't working before. Thanks again!

CBougoZ avatar Jun 14 '24 07:06 CBougoZ

No worries @CBougoZ! Glad to hear you're back up and running!

Closing the issue with the documentation merge https://github.com/aws-amplify/docs/pull/7681 https://docs.amplify.aws/react/build-a-backend/troubleshooting/cannot-find-module-amplify-env/

josefaidt avatar Jun 14 '24 17:06 josefaidt

Add a exclude still not working for me :/ image image I am using the Amplify React Template

LittleCuong avatar Jun 24 '24 02:06 LittleCuong