{"record":{"id":"c17a069456cbe0d9","repo":"transloadit/uppy","slug":"s3mini-missing-etag-in-uploadpart-response-heade","errorCode":null,"errorMessage":"[s3mini] Missing ETag in uploadPart response headers","messagePattern":"\\[s3mini\\] Missing ETag in uploadPart response headers","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/@uppy/aws-s3/src/s3-client/CompanionS3.ts","lineNumber":146,"sourceCode":"      {\n        method: 'GET',\n        signal,\n      },\n    )\n\n    const { url }: { url: string } = await response.json()\n\n    const xhr = await this._request({\n      url,\n      method: 'PUT',\n      data,\n      onProgress,\n      signal,\n    })\n\n    const etag = U.sanitizeETag(xhr.getResponseHeader('etag'))\n    if (etag == null) {\n      throw new Error(\n        `${C.ERROR_PREFIX}Missing ETag in uploadPart response headers`,\n      )\n    }\n\n    return { etag }\n  }\n\n  public override async listParts({\n    uploadId,\n    key,\n    signal,\n  }: IT.ListPartsParams): Promise<IT.UploadPart[]> {\n    if (!uploadId) {\n      throw new TypeError(C.ERROR_UPLOAD_ID_REQUIRED)\n    }\n\n    const response = await this._fetch(\n      `/multipart/${encodeURIComponent(uploadId)}?${new URLSearchParams({ key })}`,","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/transloadit/uppy/blob/5d4dedd02a1ac0ae022c75c54aca76558f88e256/packages/@uppy/aws-s3/src/s3-client/CompanionS3.ts#L128-L164","documentation":"The preauth flow is only supported for providers that expose a credentialsURL (an endpoint where Companion can exchange pre-auth tokens for real credentials). If providerOptions[providerName].credentialsURL is not set, Companion responds 501 Not Implemented.","triggerScenarios":"Calling preauth for a provider (e.g. URL/Unsplash-type flows) that does not have a credentialsURL configured in companionOptions for this deployment.","commonSituations":"Attempting preauth for a provider whose server-side setup was not completed (missing credentialsURL in providerOptions); using a Companion version where the provider does not support pre-auth; assuming all providers support preauth.","solutions":["Configure providerOptions[providerName].credentialsURL for the provider in Companion options","Only call preauth for providers that support it","Update Companion if the provider gained preauth support in a newer version"],"exampleFix":"// before\ncompanion({ providerOptions: { url: {} } })\n// after\ncompanion({ providerOptions: { url: { credentialsURL: 'https://example.com/credentials' } } })","handlingStrategy":"type-guard","validationCode":"const supportsPreauth = Boolean(providerOptions[providerName]?.credentialsURL)\nif (!supportsPreauth) throw new Error(`${providerName} does not support preauth`)","typeGuard":"const supportsPreauth = (p: string): boolean =>\n  Boolean(providerOptions[p]?.credentialsURL)","tryCatchPattern":"try {\n  await preauth(provider)\n} catch (e) {\n  if (e.status === 501) return fallbackToDirectAuth()\n  throw e\n}","preventionTips":["Check for credentialsURL config before offering preauth in the UI","Handle 501 explicitly as 'unsupported' rather than retrying"],"tags":["companion","preauth","http-501","not-implemented"],"backgroundTag":"feature-not-configured","analyzedSha":"5d4dedd02a1ac0ae022c75c54aca76558f88e256","analyzedAt":"2026-08-28T12:18:41.267Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}