{"record":{"id":"e849d7d5c5e479d3","repo":"Wei-Shaw/sub2api","slug":"json","errorCode":null,"errorMessage":"空 JSON 内容","messagePattern":"空 JSON 内容","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/internal/handler/admin/account_codex_import.go","lineNumber":468,"sourceCode":"}\n\nfunc decodeCodexJSONStream(content string) ([]any, error) {\n\tdecoder := json.NewDecoder(strings.NewReader(content))\n\tdecoder.UseNumber()\n\tvalues := make([]any, 0, 1)\n\tfor {\n\t\tvar value any\n\t\terr := decoder.Decode(&value)\n\t\tif errors.Is(err, io.EOF) {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tvalues = append(values, value)\n\t}\n\tif len(values) == 0 {\n\t\treturn nil, errors.New(\"空 JSON 内容\")\n\t}\n\treturn values, nil\n}\n\nfunc flattenCodexImportValues(values []any) []any {\n\tout := make([]any, 0, len(values))\n\tvar appendValue func(any)\n\tappendValue = func(value any) {\n\t\tif arr, ok := value.([]any); ok {\n\t\t\tfor _, item := range arr {\n\t\t\t\tappendValue(item)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tout = append(out, value)\n\t}\n\tfor _, value := range values {\n\t\tappendValue(value)","sourceCodeStart":450,"sourceCodeEnd":486,"githubUrl":"https://github.com/Wei-Shaw/sub2api/blob/073e92d17178a1ccdb0a27017f572f10c9c7ab62/backend/internal/handler/admin/account_codex_import.go#L450-L486","documentation":"Returned by the Codex session-import JSON parser (backend/internal/handler/admin/account_codex_import.go:468) when the request body decodes successfully as JSON but contains zero top-level values — i.e. the stream is only whitespace or an empty document after json.Decoder loop hits io.EOF with nothing accumulated. It guards the admin import endpoint from creating an empty import batch.","triggerScenarios":"POSTing an import payload that is an empty string, only whitespace/newlines, or comments-only JSON; uploading an empty .json file selected by mistake; a client that serializes an empty array/object incorrectly and sends an empty body with Content-Type application/json.","commonSituations":"Admin UI file-picker allowing zero-byte files; curl with an empty -d '' argument; automated export that wrote no records and the operator re-imports the empty artifact; clipboard paste of nothing into the import textarea.","solutions":["Provide at least one valid JSON value (object or array of objects) in the import body, e.g. one Codex auth.json document.","If importing from a file, verify the file is non-empty and contains the expected exported auth.json content before uploading.","In the admin UI, add a client-side check that rejects empty/whitespace-only input before submitting."],"exampleFix":"// before\ncurl -X POST /admin/codex/import -H 'Content-Type: application/json' -d ''\n\n// after\ncurl -X POST /admin/codex/import -H 'Content-Type: application/json' -d '{\"access_token\":\"...\",\"refresh_token\":\"...\"}'","handlingStrategy":"validation","validationCode":"function hasJsonContent(text: string): boolean {\n  return JSON.parse(text) !== undefined && text.trim() !== ''\n}\n// Go side, before calling the decoder:\nif strings.TrimSpace(string(body)) == \"\" {\n    return errors.New(\"empty payload\")\n}","typeGuard":null,"tryCatchPattern":"values, err := decodeCodexValues(body)\nif err != nil {\n    if err.Error() == \"空 JSON 内容\" {\n        http.Error(w, \"upload a non-empty JSON export\", http.StatusBadRequest)\n        return\n    }\n    http.Error(w, err.Error(), http.StatusBadRequest)\n}","preventionTips":["Client-side: reject empty or whitespace-only files/text before POSTing the import.","Check the selected file's size > 0 in the admin UI file picker.","After exporting, sanity-check the artifact contains at least one JSON object before re-importing."],"tags":["admin","import","json","validation","backend","codex"],"backgroundTag":null,"analyzedSha":"073e92d17178a1ccdb0a27017f572f10c9c7ab62","analyzedAt":"2026-08-15T14:33:00.750Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}