{"record":{"id":"57137bd7a8ec0c7d","repo":"usememos/memos","slug":"invalidargument-57137b","errorCode":"InvalidArgument","errorMessage":"invalid data URI format","messagePattern":"invalid data URI format","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"server/router/api/v1/user_service_converters.go","lineNumber":77,"sourceCode":"\t}\n}\n\nfunc convertUserRoleToStore(role v1pb.User_Role) store.Role {\n\tswitch role {\n\tcase v1pb.User_ADMIN:\n\t\treturn store.RoleAdmin\n\tdefault:\n\t\treturn store.RoleUser\n\t}\n}\n\n// extractImageInfo extracts image type and base64 data from a data URI.\n// Data URI format: data:image/png;base64,iVBORw0KGgo...\nfunc extractImageInfo(dataURI string) (string, string, error) {\n\tdataURIRegex := regexp.MustCompile(`^data:(?P<type>.+);base64,(?P<base64>.+)`)\n\tmatches := dataURIRegex.FindStringSubmatch(dataURI)\n\tif len(matches) != 3 {\n\t\treturn \"\", \"\", errors.New(\"invalid data URI format\")\n\t}\n\timageType := matches[1]\n\tbase64Data := matches[2]\n\treturn imageType, base64Data, nil\n}\n\n// convertSettingKeyToStore converts API setting key to store enum.\nfunc convertSettingKeyToStore(key string) (storepb.UserSetting_Key, error) {\n\tswitch key {\n\tcase v1pb.UserSetting_Key_name[int32(v1pb.UserSetting_GENERAL)]:\n\t\treturn storepb.UserSetting_GENERAL, nil\n\tcase v1pb.UserSetting_Key_name[int32(v1pb.UserSetting_WEBHOOKS)]:\n\t\treturn storepb.UserSetting_WEBHOOKS, nil\n\tcase v1pb.UserSetting_Key_name[int32(v1pb.UserSetting_TAGS)]:\n\t\treturn storepb.UserSetting_TAGS, nil\n\tdefault:\n\t\treturn storepb.UserSetting_KEY_UNSPECIFIED, errors.Errorf(\"unknown setting key: %s\", key)\n\t}","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/server/router/api/v1/user_service_converters.go#L59-L95","documentation":"extractImageInfo parses avatar data URIs with the regex ^data:(?P<type>.+);base64,(?P<base64>.+). It returns this error when the string does not contain the ';base64,' separator structure — e.g. URL-encoded images, plain base64 without the data: prefix, or data URIs with non-base64 encodings. The regex is anchored, so leading/trailing characters also fail. Surfaced as InvalidArgument.","triggerScenarios":"UpdateUser avatar set to 'data:image/png' (truncated), raw 'iVBORw0KGgo...' without the data URI wrapper, 'data:image/webp,url=...' style URIs, or a URI where the base64 payload is empty.","commonSituations":"Frontend using blob: or object URLs instead of reading the File as a data URL via FileReader; third-party avatar URLs passed instead of inline data; size-limited proxies truncating the header.","solutions":["Produce the data URI with FileReader.readAsDataURL(file) (or canvas.toDataURL) which always yields data:<mime>;base64,<data>.","If you already have raw base64, wrap it: `data:image/png;base64,${b64}`.","Ensure the mime type is present and the payload non-empty before sending."],"exampleFix":"// before\navatar = rawBase64String; // 'iVBORw0KGgo...'\n\n// after\navatar = `data:image/png;base64,${rawBase64String}`;\n// or from a File: const avatar = await fileToDataUrl(file);","handlingStrategy":"type-guard","validationCode":"const DATA_URI_RE = /^data:[^;]+;base64,.+$/;\nif (!DATA_URI_RE.test(avatar)) throw new Error('Avatar must be a data:<type>;base64,<data> URI');","typeGuard":"function isBase64DataUri(v) {\n  return typeof v === 'string' && /^data:[^;]+;base64,[A-Za-z0-9+/=]+$/.test(v);\n}","tryCatchPattern":null,"preventionTips":["Always generate avatar data URIs with FileReader.readAsDataURL or canvas.toDataURL.","Never pass blob:/object URLs or remote image URLs where inline data is expected.","Wrap raw base64 as `data:<mime>;base64,${b64}` before sending."],"tags":["validation","avatar","data-uri","base64","invalid-argument"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}