{"record":{"id":"83c550a6550a6200","repo":"langgenius/dify","slug":"context-requires-formdata","errorCode":null,"errorMessage":"${context} requires FormData","messagePattern":"(.+?) requires FormData","errorType":"validation","errorClass":"FileUploadError","httpStatus":null,"severity":"error","filePath":"sdks/nodejs-client/src/client/knowledge-base.ts","lineNumber":46,"sourceCode":"  DatasourceNodeRunRequest,\n  PipelineRunRequest,\n  KnowledgeBaseResponse,\n  PipelineStreamEvent,\n} from '../types/knowledge-base'\nimport { FileUploadError, ValidationError } from '../errors/dify-error'\nimport { isFormData } from '../http/form-data'\nimport { DifyClient } from './base'\nimport {\n  ensureNonEmptyString,\n  ensureOptionalBoolean,\n  ensureOptionalInt,\n  ensureOptionalString,\n  ensureStringArray,\n} from './validation'\n\nfunction ensureFormData(form: unknown, context: string): asserts form is SdkFormData {\n  if (!isFormData(form)) {\n    throw new FileUploadError(`${context} requires FormData`)\n  }\n}\n\nconst ensureNonEmptyArray = (value: unknown, name: string): void => {\n  if (!Array.isArray(value) || value.length === 0) {\n    throw new ValidationError(`${name} must be a non-empty array`)\n  }\n}\n\nexport class KnowledgeBaseClient extends DifyClient {\n  async listDatasets(options?: DatasetListOptions): Promise<DifyResponse<KnowledgeBaseResponse>> {\n    ensureOptionalInt(options?.page, 'page')\n    ensureOptionalInt(options?.limit, 'limit')\n    ensureOptionalString(options?.keyword, 'keyword')\n    ensureOptionalBoolean(options?.includeAll, 'includeAll')\n\n    const query: QueryParams = {\n      page: options?.page,","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/sdks/nodejs-client/src/client/knowledge-base.ts#L28-L64","documentation":"Thrown by the private ensureFormData() helper in knowledge-base.ts:46 as a FileUploadError. Three knowledge-base methods use it — createDocumentByFile, updateDocumentByFile, and uploadPipelineFile — each passing a context string so the message identifies which call site rejected the non-FormData argument. Like error 120, it requires a genuine FormData instance because the underlying endpoints are multipart uploads.","triggerScenarios":"Calling knowledgeBase.createDocumentByFile(datasetId, payload, user) (or updateDocumentByFile / uploadPipelineFile) where payload is not a FormData: a plain object, a Buffer, a string path, or undefined. The assert at knowledge-base.ts:45 fails and the FileUploadError is thrown synchronously with the method name interpolated.","commonSituations":"Switching from the text-based createDocumentByText to the file variant and forgetting to wrap the file in FormData; passing { file, data } as a JSON object; using an outdated form library whose instances fail isFormData(); Node environments without a FormData global and no polyfill.","solutions":["Build a FormData, append both 'file' and the 'data' JSON field the server expects, then pass it: const form = new FormData(); form.append('file', fileHandle); form.append('data', JSON.stringify({...})); await kb.createDocumentByFile(datasetId, form, user).","On Node < 18 import a form-data polyfill so isFormData() returns true via getHeaders() or constructor.name.","Use createDocumentByText(datasetId, { name, text, ... }, user) instead if you only have raw text and want to avoid multipart entirely.","Verify the variable you pass is the FormData instance itself, not a wrapper object holding it."],"exampleFix":"// before\nawait kb.createDocumentByFile(datasetId, { name: 'doc', file: '/p.pdf' }, user)\n\n// after\nimport FormData from 'form-data'\nconst form = new FormData()\nform.append('file', fs.createReadStream('/p.pdf'))\nform.append('data', JSON.stringify({ name: 'doc', indexing_technique: 'high_quality' }))\nawait kb.createDocumentByFile(datasetId, form, user)","handlingStrategy":"type-guard","validationCode":"import { isFormData } from '@dify-platform/dify-client/src/http/form-data'\nfunction assertDocForm(form: unknown, ctx: string) {\n  if (!isFormData(form)) throw new Error(`${ctx} requires FormData`)\n}","typeGuard":"import { isFormData } from '@dify-platform/dify-client/src/http/form-data'\nfunction isDocumentForm(value: unknown): value is FormData {\n  return isFormData(value)\n}","tryCatchPattern":"try {\n  await kb.createDocumentByFile(ds, form, user)\n} catch (err) {\n  if (err instanceof Error && err.name === 'FileUploadError' && /requires FormData/.test(err.message)) {\n    // rebuild form and retry once\n  } else throw err\n}","preventionTips":["Centralize document-upload form construction in one helper so the same FormData shape is reused.","Prefer createDocumentByText when you have only text content.","Log form.constructor.name in dev to confirm isFormData recognition."],"tags":["validation","form-data","knowledge-base","document-upload","multipart"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}