Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 6a35ea3b61 fix: handle ResourceConflictException in LambdaDriver.build() for concurrent executions
https://sonarly.com/issue/16137?type=bug

The `LambdaDriver.build()` method has a TOCTOU race condition: it checks if an AWS Lambda function exists (GET → 404), then creates it (POST → 409 conflict), without handling the case where another concurrent worker creates the same function between the check and create.

Fix: **What changed:** Added `ResourceConflictException` handling to all three `CreateFunctionCommand` call sites in `LambdaDriver`:

1. **`build()`** (line 738) — the main logic function executor Lambda creation, which is the exact call site in the Sentry stack trace
2. **`ensureYarnInstallLambdaExists()`** (line 358) — the yarn-install helper Lambda creation
3. **`ensureBuilderLambdaExists()`** (line 454) — the esbuild transpiler helper Lambda creation

All three methods had the same TOCTOU race condition: check if function exists → get 404 → try to create → 409 because another concurrent worker already created it.

**Pattern:** The fix uses the exact same error-handling pattern already established in the file for `ResourceNotFoundException` — catch the specific AWS SDK exception, re-throw anything else. When `ResourceConflictException` is caught, execution continues normally because the function now exists (created by the other concurrent worker), and `waitFunctionActive` (called after `build()`) will wait for it to be ready.

**Import:** Added `ResourceConflictException` to the existing `@aws-sdk/client-lambda` import block, alphabetically next to the already-imported `ResourceNotFoundException`.
2026-03-18 22:08:28 +00:00
@@ -15,6 +15,7 @@ import {
type ListLayerVersionsCommandInput,
LogType,
PublishLayerVersionCommand,
ResourceConflictException,
ResourceNotFoundException,
waitUntilFunctionActiveV2,
} from '@aws-sdk/client-lambda';
@@ -355,7 +356,13 @@ export class LambdaDriver implements LogicFunctionDriver {
MemorySize: YARN_INSTALL_LAMBDA_MEMORY_MB,
};
await lambdaClient.send(new CreateFunctionCommand(params));
try {
await lambdaClient.send(new CreateFunctionCommand(params));
} catch (error) {
if (!(error instanceof ResourceConflictException)) {
throw error;
}
}
} finally {
await temporaryDirManager.clean();
}
@@ -444,7 +451,13 @@ export class LambdaDriver implements LogicFunctionDriver {
MemorySize: BUILDER_LAMBDA_MEMORY_MB,
};
await lambdaClient.send(new CreateFunctionCommand(params));
try {
await lambdaClient.send(new CreateFunctionCommand(params));
} catch (error) {
if (!(error instanceof ResourceConflictException)) {
throw error;
}
}
} finally {
await temporaryDirManager.clean();
}
@@ -725,7 +738,14 @@ export class LambdaDriver implements LogicFunctionDriver {
const command = new CreateFunctionCommand(params);
await (await this.getLambdaClient()).send(command);
try {
await (await this.getLambdaClient()).send(command);
} catch (error) {
if (!(error instanceof ResourceConflictException)) {
throw error;
}
// Function was concurrently created by another worker — safe to proceed
}
await temporaryDirManager.clean();
}