{"record":{"id":"01c46b61f2fbf73b","repo":"maotoumao/MusicFree","slug":"panel-imageviewer-saveimagefail","errorCode":"panel.imageViewer.saveImageFail","errorMessage":"panel.imageViewer.saveImageFail","messagePattern":"panel\\.imageViewer\\.saveImageFail","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/components/panels/types/imageViewer.tsx","lineNumber":59,"sourceCode":"                        }\r\n                }\r\n                source={{\r\n                    uri: url,\r\n                }}\r\n            />\r\n            <Button\r\n                text={t(\"panel.imageViewer.saveImage\")}\r\n                type=\"primary\"\r\n                style={styles.button}\r\n                onPress={() => {\r\n                    saveToGallery(url)\r\n                        .then((resultPath) => {\r\n                            Toast.success(t(\"panel.imageViewer.saveImageSuccess\", {\r\n                                path: resultPath,\r\n                            }));\r\n                        }).catch(e => {\r\n                            errorLog(\"Save failed\", e?.message ?? e);\r\n                            Toast.warn(t(\"panel.imageViewer.saveImageFail\", {\r\n                                reason: e?.message ?? e,\r\n                            }));\r\n                        });\r\n                }}\r\n            />\r\n        </PanelFullscreen>\r\n    );\r\n}\r\n\r\nconst styles = StyleSheet.create({\r\n    container: {\r\n        justifyContent: \"center\",\r\n        alignItems: \"center\",\r\n        gap: rpx(48),\r\n    },\r\n    button: {\r\n        marginHorizontal: rpx(24),\r\n        paddingHorizontal: rpx(200),\r","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/maotoumao/MusicFree/blob/d118b18b3d0c904400f7eea7bf99c0ceec6c1aee/src/components/panels/types/imageViewer.tsx#L41-L77","documentation":"In the image viewer panel (src/components/panels/types/imageViewer.tsx), saving an image resolves with a resultPath on success; on rejection the catch logs the error and toasts t('panel.imageViewer.saveImageFail', {reason}). The message 'panel.imageViewer.saveImageFail' is an untranslated i18n key, shown when the translation is missing or t receives only the key, with the underlying native save failure as the reason.","triggerScenarios":"Tapping save in the image viewer when the native save (download to gallery / file write) rejects: no storage permission, invalid source URL, network failure fetching the image, or the destination path being unwritable.","commonSituations":"Android storage permission not granted; image URL expired or blocked by the source site; saving on a device with full storage; i18n resource missing the panel.imageViewer.* keys so the raw key appears in the toast.","solutions":["Grant storage/photos permission to the app, then retry the save.","Check 'Save failed' in the error log for the real reason (network vs permission vs path) and address it.","Add the panel.imageViewer.saveImageFail/Success keys to all locale files so users see the actual reason.","Verify the image URL is reachable (open it in a browser) and retry."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const reachable = await fetch(imageUrl, { method: 'HEAD' }).then(r => r.ok).catch(() => false);\nif (!reachable) { Toast.warn('image unavailable'); return; }\nconst hasPerm = await checkStoragePermission();\nif (!hasPerm) await requestStoragePermission();","typeGuard":null,"tryCatchPattern":"saveImage(imageUrl)\n  .then(path => Toast.success(t('panel.imageViewer.saveImageSuccess', { path })))\n  .catch(e => {\n    errorLog('Save failed', e?.message ?? e);\n    Toast.warn(t('panel.imageViewer.saveImageFail', { reason: e?.message ?? e }));\n  });","preventionTips":["Ensure the panel.imageViewer.* i18n keys exist in every locale file.","Request storage permission lazily right before the first save.","Check image URL validity/expiry before offering save.","Log the underlying error (already done via errorLog) to distinguish network vs permission causes."],"tags":["i18n","image-save","permission","toast","native"],"backgroundTag":"image-save-failed","analyzedSha":"d118b18b3d0c904400f7eea7bf99c0ceec6c1aee","analyzedAt":"2026-08-30T11:49:12.932Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}