{"record":{"id":"3b57711ab59660ae","repo":"Stirling-Tools/Stirling-PDF","slug":"missing-stored-file-id-for-sharing","errorCode":null,"errorMessage":"Missing stored file ID for sharing.","messagePattern":"Missing stored file ID for sharing\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/editor/src/core/components/shared/ShareFileModal.tsx","lineNumber":148,"sourceCode":"\n        for (const stub of chain) {\n          actions.updateStirlingFileStub(stub.id, {\n            remoteStorageId: newStoredId,\n            remoteStorageUpdatedAt: updatedAt,\n            remoteOwnedByCurrentUser: true,\n            remoteHasShareLinks: true,\n          });\n          await fileStorage.updateFileMetadata(stub.id, {\n            remoteStorageId: newStoredId,\n            remoteStorageUpdatedAt: updatedAt,\n            remoteOwnedByCurrentUser: true,\n            remoteHasShareLinks: true,\n          });\n        }\n      }\n\n      if (!storedId) {\n        throw new Error(\"Missing stored file ID for sharing.\");\n      }\n      const shareResponse = await createShareLink(storedId);\n      setShareToken(shareResponse.token ?? null);\n\n      alert({\n        alertType: \"success\",\n        title: t(\"storageShare.generated\", \"Share link generated\"),\n        expandable: false,\n        durationMs: 3000,\n      });\n      if (storedId) {\n        actions.updateStirlingFileStub(file.id, { remoteHasShareLinks: true });\n        await fileStorage.updateFileMetadata(file.id, {\n          remoteHasShareLinks: true,\n        });\n      }\n      if (onUploaded) {\n        await onUploaded();","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/core/components/shared/ShareFileModal.tsx#L130-L166","documentation":"Thrown in ShareFileModal when storedId is falsy after the upload/refresh logic completes. storedId is read from file.remoteStorageId and optionally updated via uploadHistoryChain(). If neither the existing metadata nor the upload produced a remote ID, the share link API cannot be called because createShareLink(storedId) requires a valid server-side file identifier.","triggerScenarios":"The file was never uploaded to remote storage (remoteStorageId is null) AND the uploadHistoryChain() call returned an empty remoteId. This happens when the upload endpoint fails silently, returns an unexpected shape, or the file is too large and the upload was rejected without throwing.","commonSituations":"File exceeds server upload size limit but the error was swallowed. Remote storage service is down and uploadHistoryChain returned without setting remoteId. IndexedDB metadata is stale and isUpToDate check incorrectly skipped the upload branch.","solutions":["Verify uploadHistoryChain() return value has a non-null remoteId before proceeding — log and surface the upload error if it doesn't.","Check the server's upload endpoint response shape matches { remoteId, updatedAt } — a version mismatch could return a different field name.","Add explicit error handling around uploadHistoryChain() to catch network failures instead of relying on the downstream storedId check.","If remoteStorageId is already set but stale, force a re-upload rather than silently skipping."],"exampleFix":"// before\nconst { remoteId: newStoredId, updatedAt, chain } = await uploadHistoryChain(originalFileId, remoteId);\nstoredId = newStoredId;\n// ... later ...\nif (!storedId) {\n  throw new Error(\"Missing stored file ID for sharing.\");\n}\n\n// after\nconst { remoteId: newStoredId, updatedAt, chain } = await uploadHistoryChain(originalFileId, remoteId);\nif (!newStoredId) {\n  throw new Error(\"Upload failed — the server did not return a file ID. Check upload limits and try again.\");\n}\nstoredId = newStoredId;","handlingStrategy":"validation","validationCode":"// Validate remoteStorageId exists before opening the share modal\nconst canShare = Boolean(file.remoteStorageId) || Boolean(file.originalFileId);\nif (!canShare) {\n  showAlert('File must be uploaded before sharing.');\n  return;\n}\n// Also validate uploadHistoryChain result:\nif (!newStoredId) {\n  throw new Error('Upload did not return a file ID — check server upload limits.');\n}","typeGuard":"function hasRemoteStorageId(file: StirlingFileStub): file is StirlingFileStub & { remoteStorageId: string } {\n  return typeof file.remoteStorageId === 'string' && file.remoteStorageId.length > 0;\n}","tryCatchPattern":"try {\n  const result = await uploadHistoryChain(originalFileId, remoteId);\n  if (!result.remoteId) {\n    setErrorMessage('Upload failed. Please check your connection and try again.');\n    return;\n  }\n  // proceed with share\n} catch (error) {\n  setErrorMessage(`Failed to prepare file for sharing: ${error instanceof Error ? error.message : 'unknown error'}`);\n}","preventionTips":["Check file.remoteStorageId is truthy before enabling the share button.","Wrap uploadHistoryChain in explicit error handling — don't rely on the downstream storedId check.","Verify server upload size limits match the file being shared.","Test the share flow with files that have never been uploaded (cold path) separately from already-stored files."],"tags":["file-storage","sharing","remote-storage","upload","validation"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}