adding onUploadProgress makes the api failed
I am trying to upload to s3 using pre-signed url. Here is the code for that:
const handleImageChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
try {
// Get presigned URL from the server
const file = e.target.files?.[0];
if (!file) {
toast.error("No file selected");
return;
}
const formData = new FormData();
formData.append("file_name", file.name);
formData.append("file_type", file.type);
formData.append("file_size", file.size.toString());
// Get presigned URL from the server
const presignedUrlResponse = await apiClient<PresignedUrlType>(
`/api/proxy/options/generate-presigned-url`,
{ method: "post", body: formData }
);
if (presignedUrlResponse.status !== 200) {
toast.error("Failed to get presigned URL");
return;
}
const presignedUrlData = await presignedUrlResponse.json();
const presignedUrl = presignedUrlData.data.presigned_url;
// Upload the file to the presigned URL
const uploadResponse = await ky.put(presignedUrl, {
body: file,
});
} catch (error) {
console.error((error as Error).message);
}
};
And as expected it works fine. But when I am adding onUploadProgress it is failing to upload:
const handleImageChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
try {
// Get presigned URL from the server
const file = e.target.files?.[0];
if (!file) {
toast.error("No file selected");
return;
}
const formData = new FormData();
formData.append("file_name", file.name);
formData.append("file_type", file.type);
formData.append("file_size", file.size.toString());
// Get presigned URL from the server
const presignedUrlResponse = await apiClient<PresignedUrlType>(
`/api/proxy/options/generate-presigned-url`,
{ method: "post", body: formData }
);
if (presignedUrlResponse.status !== 200) {
toast.error("Failed to get presigned URL");
return;
}
const presignedUrlData = await presignedUrlResponse.json();
const presignedUrl = presignedUrlData.data.presigned_url;
// Upload the file to the presigned URL
const uploadResponse = await ky.put(presignedUrl, {
body: file,
onUploadProgress: (progress, chunk) => {
// Example output:
// `0% - 0 of 1271 bytes`
// `100% - 1271 of 1271 bytes`
console.log(
`${progress.percent * 100}% - ${progress.transferredBytes} of ${
progress.totalBytes
} bytes`
);
},
});
} catch (error) {
console.error((error as Error).message);
}
};
Here is the full log:
99% - 30627 of 30627 bytes
100% - 30627 of 30627 bytes
QRCodeForm.tsx:147 PUT https://potential-dev2.s3.amazonaws.com/e4p_dev/private/dir_20250916_011143_0873/qr%20%281%29.svg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAU6GDX3LAHVYE7YBU%2F20250915%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Date=20250915T161143Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=700c264680156ba2466f4e7484f5423700626b114d7ef37e8f5911e630000bc7 net::ERR_ALPN_NEGOTIATION_FAILED
(anonymous) @ timeout.ts:25
timeout @ timeout.ts:15
_fetch @ Ky.ts:338
function_ @ Ky.ts:42
await in function_
_retry @ Ky.ts:285
create @ Ky.ts:87
ky.<computed> @ index.ts:16
handleImageChange @ QRCodeForm.tsx:147
await in handleImageChange
executeDispatch @ react-dom-client.development.js:21336
runWithFiberInDEV @ react-dom-client.development.js:996
processDispatchQueue @ react-dom-client.development.js:21386
(anonymous) @ react-dom-client.development.js:21985
batchedUpdates$1 @ react-dom-client.development.js:3334
dispatchEventForPluginEventSystem @ react-dom-client.development.js:21540
dispatchEvent @ react-dom-client.development.js:26873
dispatchDiscreteEvent @ react-dom-client.development.js:26841
QRCodeForm.tsx:147 PUT https://potential-dev2.s3.amazonaws.com/e4p_dev/private/dir_20250916_011143_0873/qr%20%281%29.svg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAU6GDX3LAHVYE7YBU%2F20250915%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Date=20250915T161143Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=700c264680156ba2466f4e7484f5423700626b114d7ef37e8f5911e630000bc7 net::ERR_ALPN_NEGOTIATION_FAILED
(anonymous) @ timeout.ts:25
timeout @ timeout.ts:15
_fetch @ Ky.ts:338
function_ @ Ky.ts:42
await in function_
_retry @ Ky.ts:285
_retry @ Ky.ts:309
await in _retry
create @ Ky.ts:87
ky.<computed> @ index.ts:16
handleImageChange @ QRCodeForm.tsx:147
await in handleImageChange
executeDispatch @ react-dom-client.development.js:21336
runWithFiberInDEV @ react-dom-client.development.js:996
processDispatchQueue @ react-dom-client.development.js:21386
(anonymous) @ react-dom-client.development.js:21985
batchedUpdates$1 @ react-dom-client.development.js:3334
dispatchEventForPluginEventSystem @ react-dom-client.development.js:21540
dispatchEvent @ react-dom-client.development.js:26873
dispatchDiscreteEvent @ react-dom-client.development.js:26841
QRCodeForm.tsx:147 PUT https://potential-dev2.s3.amazonaws.com/e4p_dev/private/dir_20250916_011143_0873/qr%20%281%29.svg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAU6GDX3LAHVYE7YBU%2F20250915%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Date=20250915T161143Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=700c264680156ba2466f4e7484f5423700626b114d7ef37e8f5911e630000bc7 net::ERR_ALPN_NEGOTIATION_FAILED
Also the upload progress it is logging is fake:
99% - 30627 of 30627 bytes
100% - 30627 of 30627 bytes
Can you use the network tab to show us the request headers, both with and without onUploadProgress?
Can you use the network tab to show us the request headers, both with and without
onUploadProgress?
Without onUploadProgress:
With onUploadProgress:
Here it is @sholladay
Thanks, looks like a bug to me. If you can find a way to make a minimal reproducible example that I could run on my machine, that would be useful.
I am working on re-writing the uploadProgress logic right now, so it would be good to see if my changes fix this or not.
Thanks, looks like a bug to me. If you can find a way to make a minimal reproducible example that I could run on my machine, that would be useful.
I am working on re-writing the
uploadProgresslogic right now, so it would be good to see if my changes fix this or not.
I've made a minimal reproducible example here. Clone this repo and checkout the ky-upload branch, then run node ./server.js start the service.
Hope it helps.
Same here, we get an ERR_ALPN_NEGOTIATION_FAILED error when using with onUploadProgress to post form data to a Next.js API route.
Same here, we get an ERR_ALPN_NEGOTIATION_FAILED error when using with onUploadProgress to post form data to a Next.js API route.
https://github.com/sindresorhus/ky/issues/733#issuecomment-3276676330
Ky v1.11.0 includes a rewrite of the progress callbacks and resolves a number of small bugs and inconsistencies. I haven't investigated this particular issue yet, but the update is worth a try if you haven't already.
Ky v1.11.0 includes a rewrite of the progress callbacks and resolves a number of small bugs and inconsistencies. I haven't investigated this particular issue yet, but the update is worth a try if you haven't already.
I tried Ky v1.13.0, but it failed again. I can reproduce in Microsoft Edge 141.0.3537.99 and Google Chrome 144.0.7501.2
Testing Env: ky 1.13.0; Vue 3.5.22; chrome: 141 Expection: POST http://localhost:5173/api/uploadtest net::ERR_ALPN_NEGOTIATION_FAILED
// code is simple const api = ky.extend({ prefixUrl: '/api/', retry: 0, }) export async function upload(url: string, data: FormData) { await api.post(url, { body: data, // working without onUploadProgress onUploadProgress: (progress) => { console.log('onUploadProgress') }, }) }
without onUploadProgress, Request headers