{"record":{"id":"e2fe9631a1bf5bf6","repo":"chatboxai/chatbox","slug":"preview-not-available","errorCode":null,"errorMessage":"Preview not available","messagePattern":"Preview not available","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/renderer/modals/ArtifactPreview.tsx","lineNumber":39,"sourceCode":"import * as toastActions from '@/stores/toastActions'\n\nexport interface ArtifactPreviewProps {\n  htmlCode: string\n  previewUrl?: string\n  sandboxPath?: string\n  uniqueId?: string\n  sessionId?: string\n}\n\nfunction decodeBase64Utf8(base64: string): string {\n  const binary = atob(base64)\n  const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0))\n  return new TextDecoder().decode(bytes)\n}\n\nasync function readSandboxHtml(sandboxPath: string): Promise<string> {\n  if (!platform.sandboxReadFileBase64) {\n    throw new Error('Preview not available')\n  }\n  const res = await platform.sandboxReadFileBase64({ filePath: sandboxPath })\n  if (!res.success || !res.base64) {\n    throw new Error(res.error || 'Preview not available')\n  }\n  return inlineSandboxHtmlAssets(decodeBase64Utf8(res.base64), sandboxPath, (assetPath) => {\n    if (!platform.sandboxReadFileBase64) {\n      return Promise.resolve({ success: false })\n    }\n    return platform.sandboxReadFileBase64({ filePath: assetPath })\n  })\n}\n\nconst ArtifactPreview = NiceModal.create((props: ArtifactPreviewProps) => {\n  const { htmlCode, previewUrl, sandboxPath, uniqueId, sessionId } = props\n  const modal = useModal()\n  const { t } = useTranslation()\n  const [reloadSign, setReloadSign] = useState(0)","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/renderer/modals/ArtifactPreview.tsx#L21-L57","documentation":"Thrown by readSandboxHtml (src/renderer/modals/ArtifactPreview.tsx:39) when the current platform has not implemented the optional platform.sandboxReadFileBase64 capability. The function is called from onPublish when publishing a sandboxed HTML artifact that has no inline htmlCode. Because sandbox reading is an optional platform interface method (see platform/interfaces.ts), platforms/shells that omit it cannot publish sandbox-only artifacts and hit this guard before any I/O.","triggerScenarios":"ArtifactPreview.onPublish is invoked with an artifact whose htmlCode is empty but sandboxPath is set (canPublish true via sandboxPath), so readSandboxHtml(sandboxPath) runs. On a platform where platform.sandboxReadFileBase64 is undefined, the very first check throws 'Preview not available'. The publish then fails and the catch at line 83 shows a toast.","commonSituations":"Running the app on a platform variant that did not wire up sandbox file access (some mobile/embedded shells); a new target platform that reuses the renderer but not the desktop platform implementation; opening a shared/synced artifact whose source is only in the sandbox on a platform without sandbox support.","solutions":["Disable or hide the Publish action on platforms without platform.sandboxReadFileBase64 (guard canPublish on the capability, not just on sandboxPath).","Ensure the artifact carries inline htmlCode so publish does not depend on reading the sandbox.","If you maintain a platform adapter, implement sandboxReadFileBase64 to read files from the sandbox and return { success, base64 }.","Catch the error and show a clear 'publish not supported on this device' message rather than a generic failure."],"exampleFix":"// before\nconst canPublish = htmlCode.trim().length > 0 || !!sandboxPath\n\n// after (only offer sandbox-backed publish where the capability exists)\nconst canPublish =\n  htmlCode.trim().length > 0 || (!!sandboxPath && !!platform.sandboxReadFileBase64)","handlingStrategy":"validation","validationCode":"// Gate publish on the capability, not just on having a sandbox path\nconst canPublish =\n  htmlCode.trim().length > 0 || (!!sandboxPath && !!platform.sandboxReadFileBase64)","typeGuard":"// Narrow the optional platform capability before calling\nfunction canReadSandbox(\n  p: { sandboxReadFileBase64?: (...a: any[]) => any }\n): p is { sandboxReadFileBase64: (params: { filePath: string }) => Promise<{ success: boolean; base64?: string; error?: string }> } {\n  return typeof p.sandboxReadFileBase64 === 'function'\n}","tryCatchPattern":"// onPublish already catches; keep the capability guard to avoid offering publish\ntry {\n  const html = htmlCode.trim() ? htmlCode : await readSandboxHtml(sandboxPath || '')\n} catch (e) {\n  toastActions.add((e as Error)?.message || t('Publish failed'))\n}","preventionTips":["Feature-detect platform.sandboxReadFileBase64 before showing the Publish button for sandbox-only artifacts.","Prefer inline htmlCode for artifacts that must be publishable across all platforms.","Implement the capability in any new platform adapter that ships the renderer.","Do not assume desktop behavior on mobile/embedded shells."],"tags":["platform","sandbox","preview","publish","capability"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}