{"record":{"id":"0dad3dd5651bdd14","repo":"siyuan-note/siyuan","slug":"invalid-block-ref-check-scope","errorCode":null,"errorMessage":"invalid block ref check scope","messagePattern":"invalid block ref check scope","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/block_remaining.go","lineNumber":134,"sourceCode":"\t\tif request.DeletedIDs, err = readArray(\"deletedIDs\", false, false); err != nil {\n\t\t\treturn\n\t\t}\n\tcase \"documents\":\n\t\trequest.Paths, err = readArray(\"paths\", true, true)\n\t\treturn\n\tcase \"notebook\":\n\t\t// 附带块 ID 只参与租约准入，沿用仅收集字符串的规则。\n\t\tvar entries []json.RawMessage\n\t\tif json.Unmarshal(fields[\"ids\"], &entries) == nil {\n\t\t\tfor _, entry := range entries {\n\t\t\t\tvar id string\n\t\t\t\tif !bytes.Equal(entry, []byte(\"null\")) && json.Unmarshal(entry, &id) == nil {\n\t\t\t\t\trequest.IDs = append(request.IDs, id)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tdefault:\n\t\treturn request, errors.New(\"invalid block ref check scope\")\n\t}\n\tif raw := fields[\"notebook\"]; len(raw) != 0 && !bytes.Equal(raw, []byte(\"null\")) {\n\t\tif json.Unmarshal(raw, &request.Notebook) != nil {\n\t\t\treturn request, errors.New(\"Field [notebook] should be of type [String]\")\n\t\t}\n\t} else if request.Scope == \"notebook\" {\n\t\treturn request, errors.New(\"Field [notebook] is required\")\n\t}\n\tif request.Scope == \"notebook\" {\n\t\trequest.Notebook = strings.TrimSpace(request.Notebook)\n\t\tif request.Notebook == \"\" {\n\t\t\treturn request, errors.New(\"Field [notebook] must not be empty\")\n\t\t}\n\t}\n\t_ = json.Unmarshal(fields[\"id\"], &request.ID)\n\treturn\n}\n","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/block_remaining.go#L116-L152","documentation":"The scope field of /api/block/checkBlockRef accepts only \"blocks\", \"documents\", or \"notebook\" (empty defaults to \"blocks\"). Any other non-empty scope value falls through to the switch default and is rejected with this error. It is an enum-validation failure on the request's scope parameter.","triggerScenarios":"POST /api/block/checkBlockRef with \"scope\": \"doc\", \"scope\": \"Blocks\", \"scope\": \"document\", or any misspelled/unsupported value.","commonSituations":"Plugin code guessing scope names instead of copying the API enum; case-sensitivity mistakes (\"Blocks\" vs \"blocks\"); translated UI labels passed directly as the scope value; version drift where code used a scope name from a different endpoint.","solutions":["Use exactly one of \"blocks\", \"documents\", or \"notebook\"","Omit scope (or send null) to get the default \"blocks\" behavior","Normalize the caller's value with toLowerCase() and map synonyms to the valid enum before sending"],"exampleFix":"// before\nawait fetchPost(\"/api/block/checkBlockRef\", { scope: \"documents\", paths });\n// after (typo: valid scope is \"documents\" only; \"document\" is rejected)\nawait fetchPost(\"/api/block/checkBlockRef\", { scope: \"documents\", paths });\n// for per-doc use the singular name is invalid; choose scope per intent:\n// \"blocks\" + ids | \"documents\" + paths | \"notebook\" + notebook","handlingStrategy":"type-guard","validationCode":"const SCOPES = ['blocks', 'documents', 'notebook'];\nif (!SCOPES.includes(scope)) throw new Error(`unsupported scope: ${scope}`);","typeGuard":"const isValidScope = (s) => s === undefined || s === null || ['blocks', 'documents', 'notebook'].includes(s);","tryCatchPattern":"try { await fetchPost('/api/block/checkBlockRef', payload); } catch (e) { if (/invalid block ref check scope/.test(e?.message)) { payload.scope = 'blocks'; /* retry with default */ } }","preventionTips":["Use a union type 'blocks' | 'documents' | 'notebook' for scope in TypeScript","Copy scope values from API docs, never from UI labels","Rely on the default (omit scope) when the intent is block-level checks"],"tags":["api","validation","enum"],"backgroundTag":"invalid-enum-value","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"}