{"record":{"id":"f66ec9aeeb13aa1c","repo":"siyuan-note/siyuan","slug":"field-srcs-each-element-should-be-of-type-string","errorCode":null,"errorMessage":"Field [srcs]: each element should be of type [String]","messagePattern":"Field \\[srcs\\]: each element should be of type \\[String\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/file_input.go","lineNumber":30,"sourceCode":"\tfields, err := blockRequestFields(reader, path)\n\tif err != nil {\n\t\treturn request, err\n\t}\n\tsrcs, err := legacyField[[]json.RawMessage](fields, \"srcs\", \"Array\", true)\n\tif err != nil {\n\t\treturn request, err\n\t}\n\tif len(srcs) == 0 {\n\t\treturn request, fmt.Errorf(\"Field [srcs] must not be empty\")\n\t}\n\trequest.DestDir, err = legacyField[string](fields, \"destDir\", \"String\", true)\n\tif err != nil {\n\t\treturn request, err\n\t}\n\tfor _, raw := range srcs {\n\t\tvar src string\n\t\tif bytes.Equal(raw, []byte(\"null\")) || json.Unmarshal(raw, &src) != nil {\n\t\t\treturn request, fmt.Errorf(\"Field [srcs]: each element should be of type [String]\")\n\t\t}\n\t\tif trim {\n\t\t\tsrc = strings.TrimSpace(src)\n\t\t\tif src == \"\" {\n\t\t\t\treturn request, fmt.Errorf(\"Field [srcs]: path must not be empty\")\n\t\t\t}\n\t\t}\n\t\trequest.Srcs = append(request.Srcs, src)\n\t}\n\treturn\n}\n\nfunc init() {\n\tGlobalCopyFiles.decodeRequest = func(reader io.Reader) (CopyFilesRequest, error) {\n\t\treturn decodeCopyFiles(reader, \"/api/file/globalCopyFiles\", false)\n\t}\n\tWorkspaceCopyFiles.decodeRequest = func(reader io.Reader) (CopyFilesRequest, error) {\n\t\treturn decodeCopyFiles(reader, \"/api/file/workspaceCopyFiles\", true)","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/file_input.go#L12-L48","documentation":"decodeCopyFiles validates each element of the \"srcs\" array: an element that is the JSON literal null or fails json.Unmarshal into a string causes \"Field [srcs]: each element should be of type [String]\". Every source must be a JSON string path; mixed-type or null entries are rejected wholesale for the request.","triggerScenarios":"Calling the copy-files API with srcs like [\"/a.sy\", null], [\"/a.sy\", 42], or objects inside srcs; element bytes exactly equal to null also trigger it (note: no whitespace tolerance here, unlike other checks).","commonSituations":"JS arrays holding undefined serialized as null; numeric file handles/IDs passed instead of path strings; spreading objects into the srcs array by mistake.","solutions":["Make every srcs element a string path, e.g. [\"/data/2023/a.sy\"]","Strip null/undefined/non-string entries before sending","Stringify path-like values if your source of truth uses non-strings legitimately","Reuse the same validated path list you use for other file APIs"],"exampleFix":"// before\nsrcs: [\"/a.sy\", null, 3]\n// after\nsrcs: [\"/a.sy\"].filter(p => typeof p === \"string\")","handlingStrategy":"type-guard","validationCode":"function onlyStringPaths(srcs) {\n  const out = (srcs || []).filter((s) => typeof s === \"string\" && s.length > 0);\n  if (out.length !== (srcs || []).length) throw new Error(\"all srcs must be non-empty strings\");\n  return out;\n}\npayload.srcs = onlyStringPaths(srcs);","typeGuard":"const isStringArray = (v) => Array.isArray(v) && v.every((s) => typeof s === \"string\");","tryCatchPattern":"try { await copyFiles(payload); } catch (e) { if (String(e).includes(\"each element should be of type [String]\")) console.error(\"srcs contains non-string elements:\", payload.srcs); }","preventionTips":["Filter srcs to typeof string before sending","Never mix numeric IDs or null into path arrays","Coerce path-like values to strings at the source","Share one path-list sanitizer across all file APIs"],"tags":["api","validation","array","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}