Bug Report
Summary
@smithy/core@3.24.0 causes ReferenceError: Buffer is not defined in browser environments during AWS SDK request signing. The core/serde package consolidation (PR #1985, commit 8963b91) moved @smithy/util-utf8 into @smithy/core as a submodule but lost the per-file browser field mappings that previously redirected Node.js-specific code to browser-safe alternatives.
This is a sibling regression to #2022 (crypto not defined on Node 18) — both stem from the same consolidation effort losing environment-specific code paths.
Stack Trace
ReferenceError: Buffer is not defined
at fromString (buffer-from.js:12:1)
at fromUtf8 (fromUtf8.js:3:1)
at toUint8Array (toUint8Array.js:4:1)
at SignatureV4.createStringToSign (SignatureV4Base.js:33:1)
at SignatureV4.getSignature (SignatureV4.js:132:1)
at SignatureV4.signRequest (SignatureV4.js:123:1)
at async AwsSdkSigV4Signer.sign (AwsSdkSigV4Signer.js:42:1)
at async httpSigningMiddleware.js:19:1
Affected Versions
- Broken:
@smithy/core@3.24.0 (published May 8, 2026) and @smithy/core@3.24.1
- Last working:
@smithy/core@3.23.17
- Bundler: webpack 5 (likely affects all bundlers that rely on the
browser field)
Root Cause Analysis
The call chain
toUint8Array.ts
└─ import { fromUtf8 } from "./fromUtf8" ← relative import
└─ fromUtf8.ts
└─ import { fromString } from "../util-buffer-from/buffer-from"
└─ Buffer.from(input, encoding) ← 💥 doesn't exist in browser
What was lost during consolidation
Before — standalone @smithy/util-utf8@4.2.0 had per-file browser mappings in its package.json:
"browser": {
"./dist-es/fromUtf8": "./dist-es/fromUtf8.browser",
"./dist-es/toUtf8": "./dist-es/toUtf8.browser"
}
These told webpack: "when resolving ./fromUtf8 inside this package, use fromUtf8.browser.js (which uses TextEncoder) instead of fromUtf8.js (which uses Buffer.from())."
After — @smithy/core@3.24.0 only has entry-point level mappings:
"browser": {
"./dist-es/submodules/serde/index.js": "./dist-es/submodules/serde/index.browser.js"
}
This correctly routes the top-level import (@smithy/core/serde → index.browser.js), and index.browser.js correctly exports from fromUtf8.browser.ts. However, toUint8Array.ts is the same file in both entry points, and it has a relative import:
// packages/core/src/submodules/serde/util-utf8/toUint8Array.ts
import { fromUtf8 } from "./fromUtf8"; // always resolves to Node.js version
Once webpack is inside the package following relative imports, the entry-point browser mapping has no effect. The relative ./fromUtf8 resolves to fromUtf8.js (Node.js, Buffer.from()) — never fromUtf8.browser.js (browser, TextEncoder).
Why PR #2009 didn't fix this
PR #2009 (commit 7ec62a0, "fix browser bundler metadata") restructured the approach to use variant index files for browser/native. The index.browser.ts correctly imports from ./util-utf8/fromUtf8.browser. But it didn't address the internal cross-reference — toUint8Array.ts still imports from ./fromUtf8 (the Node version), and this file is shared by both index.ts and index.browser.ts.
Regression Cross-References
| Date |
Event |
Reference |
| Apr 29 |
Consolidation tracking issue opened |
#1980 |
| May 1 |
core/serde consolidation PR merged |
#1985 (commit 8963b91) |
| May 6 |
Browser metadata fix PR merged (entry-point only) |
#2009 (commit 7ec62a0) |
| May 8 |
@smithy/core@3.24.0 published — regression goes live |
npm |
| May 8 |
Sibling bug reported: crypto is not defined on Node 18 |
#2022 |
| May 11 |
@smithy/core@3.24.1 published — uuid fix only, Buffer bug persists |
npm |
Suggested Fixes
Option A — Add per-file browser mappings to @smithy/core's package.json:
"browser": {
"./dist-es/submodules/serde/util-utf8/fromUtf8.js": "./dist-es/submodules/serde/util-utf8/fromUtf8.browser.js",
"./dist-es/submodules/serde/util-utf8/toUtf8.js": "./dist-es/submodules/serde/util-utf8/toUtf8.browser.js",
"./dist-es/submodules/serde/util-buffer-from/buffer-from.js": false
}
Option B — Create a browser-specific toUint8Array.browser.ts that imports from ./fromUtf8.browser and export it from index.browser.ts.
Option C — Refactor toUint8Array.ts to use TextEncoder directly (no dependency on fromUtf8 at all), since TextEncoder is available in all modern browsers and Node.js 16+:
export const toUint8Array = (data: string | ArrayBuffer | ArrayBufferView): Uint8Array => {
if (typeof data === "string") {
return new TextEncoder().encode(data);
}
// ...
};
Current Workaround
For webpack users, inject Buffer globally via ProvidePlugin:
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
}),
],
resolve: {
fallback: {
buffer: require.resolve('buffer/'),
},
},
};
Environment
- Bundler: webpack 5
- Target: browser (ES2020)
- Framework: React 18
- AWS SDK:
@aws-sdk/client-* (latest, depends on @smithy/core@^3.24.0)
Bug Report
Summary
@smithy/core@3.24.0causesReferenceError: Buffer is not definedin browser environments during AWS SDK request signing. Thecore/serdepackage consolidation (PR #1985, commit8963b91) moved@smithy/util-utf8into@smithy/coreas a submodule but lost the per-filebrowserfield mappings that previously redirected Node.js-specific code to browser-safe alternatives.This is a sibling regression to #2022 (crypto not defined on Node 18) — both stem from the same consolidation effort losing environment-specific code paths.
Stack Trace
Affected Versions
@smithy/core@3.24.0(published May 8, 2026) and@smithy/core@3.24.1@smithy/core@3.23.17browserfield)Root Cause Analysis
The call chain
What was lost during consolidation
Before — standalone
@smithy/util-utf8@4.2.0had per-file browser mappings in itspackage.json:These told webpack: "when resolving
./fromUtf8inside this package, usefromUtf8.browser.js(which usesTextEncoder) instead offromUtf8.js(which usesBuffer.from())."After —
@smithy/core@3.24.0only has entry-point level mappings:This correctly routes the top-level import (
@smithy/core/serde→index.browser.js), andindex.browser.jscorrectly exports fromfromUtf8.browser.ts. However,toUint8Array.tsis the same file in both entry points, and it has a relative import:Once webpack is inside the package following relative imports, the entry-point browser mapping has no effect. The relative
./fromUtf8resolves tofromUtf8.js(Node.js,Buffer.from()) — neverfromUtf8.browser.js(browser,TextEncoder).Why PR #2009 didn't fix this
PR #2009 (commit
7ec62a0, "fix browser bundler metadata") restructured the approach to use variant index files for browser/native. Theindex.browser.tscorrectly imports from./util-utf8/fromUtf8.browser. But it didn't address the internal cross-reference —toUint8Array.tsstill imports from./fromUtf8(the Node version), and this file is shared by bothindex.tsandindex.browser.ts.Regression Cross-References
core/serdeconsolidation PR merged8963b91)7ec62a0)@smithy/core@3.24.0published — regression goes livecrypto is not definedon Node 18@smithy/core@3.24.1published — uuid fix only, Buffer bug persistsSuggested Fixes
Option A — Add per-file browser mappings to
@smithy/core'spackage.json:Option B — Create a browser-specific
toUint8Array.browser.tsthat imports from./fromUtf8.browserand export it fromindex.browser.ts.Option C — Refactor
toUint8Array.tsto useTextEncoderdirectly (no dependency onfromUtf8at all), sinceTextEncoderis available in all modern browsers and Node.js 16+:Current Workaround
For webpack users, inject
Bufferglobally viaProvidePlugin:Environment
@aws-sdk/client-*(latest, depends on@smithy/core@^3.24.0)