siyuan-note/siyuan · error
Field [srcs]: each element should be of type [String]
Error message
Field [srcs]: each element should be of type [String]
What it means
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.
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
Example fix
// before srcs: ["/a.sy", null, 3] // after srcs: ["/a.sy"].filter(p => typeof p === "string")
Defensive patterns
Strategy: type-guard
Validate before calling
function onlyStringPaths(srcs) {
const out = (srcs || []).filter((s) => typeof s === "string" && s.length > 0);
if (out.length !== (srcs || []).length) throw new Error("all srcs must be non-empty strings");
return out;
}
payload.srcs = onlyStringPaths(srcs); Type guard
const isStringArray = (v) => Array.isArray(v) && v.every((s) => typeof s === "string");
Try / catch
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); } Prevention
- 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
When it happens
Trigger: 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).
Common situations: JS arrays holding undefined serialized as null; numeric file handles/IDs passed instead of path strings; spreading objects into the srcs array by mistake.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- block [ ] type is locked: expected , got
- element [ ]
- Field [level] should be of type [Number]
- Field [notebook] should be of type [String]
- Field [preview] should be of type [Boolean]
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/f66ec9aeeb13aa1c.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/file_input.go:30
fields, err := blockRequestFields(reader, path)
if err != nil {
return request, err
}
srcs, err := legacyField[[]json.RawMessage](fields, "srcs", "Array", true)
if err != nil {
return request, err
}
if len(srcs) == 0 {
return request, fmt.Errorf("Field [srcs] must not be empty")
}
request.DestDir, err = legacyField[string](fields, "destDir", "String", true)
if err != nil {
return request, err
}
for _, raw := range srcs {
var src string
if bytes.Equal(raw, []byte("null")) || json.Unmarshal(raw, &src) != nil {
return request, fmt.Errorf("Field [srcs]: each element should be of type [String]")
}
if trim {
src = strings.TrimSpace(src)
if src == "" {
return request, fmt.Errorf("Field [srcs]: path must not be empty")
}
}
request.Srcs = append(request.Srcs, src)
}
return
}
func init() {
GlobalCopyFiles.decodeRequest = func(reader io.Reader) (CopyFilesRequest, error) {
return decodeCopyFiles(reader, "/api/file/globalCopyFiles", false)
}
WorkspaceCopyFiles.decodeRequest = func(reader io.Reader) (CopyFilesRequest, error) {
return decodeCopyFiles(reader, "/api/file/workspaceCopyFiles", true)View on GitHub (pinned to 9f775e8a12)