{"record":{"id":"54086b2e1fe77738","repo":"siyuan-note/siyuan","slug":"plugin-pluginlabel-returned-invalid-input-ta","errorCode":null,"errorMessage":"Plugin ${pluginLabel} returned invalid input: ${targetValidationError}","messagePattern":"Plugin (.+?) returned invalid input: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/protyle/upload/pluginEvent.ts","lineNumber":447,"sourceCode":"            return fail(new Error(`Plugin ${pluginLabel} must call respondWith synchronously before awaiting`));\n        }\n        if (!response) {\n            return processPlugin(index + 1);\n        }\n        return waitForDecision(response, task, pluginLabel, timeout).then(decision => {\n            if (decision?.action === \"cancel\") {\n                return cancel();\n            }\n            if (decision?.action !== \"replace\") {\n                throw new Error(`Plugin ${pluginLabel} returned an invalid action`);\n            }\n            const validationError = validateAssetUploadInput(decision.input);\n            if (validationError) {\n                throw new Error(`Plugin ${pluginLabel} returned invalid input: ${validationError}`);\n            }\n            const targetValidationError = validateTargetInput(decision.input, context);\n            if (targetValidationError) {\n                throw new Error(`Plugin ${pluginLabel} returned invalid input: ${targetValidationError}`);\n            }\n            task.input = cloneInput(decision.input);\n            return processPlugin(index + 1);\n        }).catch(error => error instanceof AssetUploadCanceledError ? cancel(error.message) : fail(error));\n    };\n    return processPlugin(0);\n};\n","sourceCodeStart":429,"sourceCodeEnd":455,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/app/src/protyle/upload/pluginEvent.ts#L429-L455","documentation":"Thrown by processPlugin in the asset upload pipeline when a plugin's upload decision passes basic shape validation (validateAssetUploadInput) but fails target-aware validation (validateTargetInput), e.g. the input references a target document/block that does not exist or is not acceptable in the current context. The original plugin error message is embedded so the plugin author's mistake is identifiable. This keeps malformed plugin output from entering the core upload flow.","triggerScenarios":"A plugin's handleAssetUpload (or equivalent decision callback) resolves with decision.input whose fields reference an invalid or missing upload target for the given context; validateTargetInput(decision.input, context) returns a non-empty error string.","commonSituations":"Plugins written against an older upload-input schema; plugins hardcoding document/block IDs that were deleted; plugins racing with document deletion so the target no longer exists when validation runs.","solutions":["Read the embedded targetValidationError message and fix the plugin's decision.input to reference an existing, valid target for the context","In the plugin, verify the target document/block ID via the kernel API before returning the decision","Re-check the plugin against the current upload input schema and add target validation of its own before resolving","If you are the host integrator, surface the error to the plugin author rather than retrying; retrying cannot succeed with the same input"],"exampleFix":"// before (plugin returns stale target)\nreturn { input: { targetId: deletedDocId, files } };\n// after (plugin verifies target first)\nconst target = await fetchSyncPost(\"/api/filetree/getDoc\", { id: targetId });\nif (target.code !== 0) throw new Error(`target ${targetId} no longer exists`);\nreturn { input: { targetId, files } };","handlingStrategy":"validation","validationCode":"// in the plugin, before returning the decision\nif (!input.targetId || !(await targetExists(input.targetId))) {\n  throw new Error(`invalid upload target: ${input.targetId}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await prepareAssetUpload(plugin);\n} catch (e) {\n  if (String(e.message).startsWith(\"Plugin \")) showPluginError(e.message); // plugin-author bug\n}","preventionTips":["Validate target references in the plugin before resolving the upload decision","Keep the plugin's input schema in sync with the host's validateTargetInput rules","Never hardcode document/block IDs; resolve them at upload time","Log the full decision object when validation fails to speed up debugging"],"tags":["plugin","validation","upload"],"backgroundTag":"schema-validation-failed","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}