{"record":{"id":"00fac668f1ff6e7d","repo":"hcengineering/platform","slug":"missing-or-invalid-required-parameter-class","errorCode":null,"errorMessage":"Missing or invalid required parameter: _class","messagePattern":"Missing or invalid required parameter: _class","errorType":"http","errorClass":"ApiError","httpStatus":400,"severity":"warning","filePath":"services/export/pod-export/src/server.ts","lineNumber":496,"sourceCode":"          conflictStrategy?: 'skip' | 'duplicate'\n          includeAttachments?: boolean\n          relations?: RelationPayload\n          objectId?: Ref<Doc>\n          objectSpace?: Ref<Space>\n          fieldMappers?: Record<string, Record<string, any>>\n          skipDeletedObsolete?: boolean\n          exportOnlyEffective?: boolean\n          includeChildren?: boolean\n        } = req.body\n\n        // Validate required parameters\n        if (targetWorkspace == null || typeof targetWorkspace !== 'string') {\n          measureCtx.warn(`Invalid targetWorkspace parameter: ${String(targetWorkspace)}`)\n          throw new ApiError(400, 'Missing or invalid required parameter: targetWorkspace')\n        }\n        if (_class == null || typeof _class !== 'string') {\n          measureCtx.warn(`Invalid _class parameter: ${String(_class)}`)\n          throw new ApiError(400, 'Missing or invalid required parameter: _class')\n        }\n        if (conflictStrategy !== undefined && conflictStrategy !== 'skip' && conflictStrategy !== 'duplicate') {\n          measureCtx.warn(`Invalid conflictStrategy: ${String(conflictStrategy)}`)\n          throw new ApiError(400, 'Invalid conflictStrategy. Must be \"skip\" or \"duplicate\"')\n        }\n        if (includeAttachments !== undefined && typeof includeAttachments !== 'boolean') {\n          measureCtx.warn(`Invalid includeAttachments: ${String(includeAttachments)}`)\n          throw new ApiError(400, 'Invalid includeAttachments. Must be boolean')\n        }\n\n        decodedToken = decodeToken(token)\n        if (decodedToken.extra?.readonly !== undefined) {\n          throw new ApiError(403, 'Forbidden: read-only token')\n        }\n\n        // Get target workspace info\n        const accountClient = getClient(envConfig.AccountsUrl, token)\n        const targetWsLoginInfo = await accountClient.getLoginWithWorkspaceInfo()","sourceCodeStart":478,"sourceCodeEnd":514,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/export/pod-export/src/server.ts#L478-L514","documentation":"In the same transfer endpoint, after targetWorkspace validation, _class must also be a non-null string naming the class to transfer. Otherwise the handler warns and throws this 400. This runs before the conflictStrategy and includeAttachments checks, so fix _class first when multiple validation errors exist.","triggerScenarios":"Posting to the transfer route with _class missing, null, or a non-string value (e.g. an array of classes); the transfer endpoint, unlike some export paths, does not accept arrays.","commonSituations":"Passing an array of classes to export several at once; using a class name that got serialized as an object; ommission after refactoring a client that previously targeted the export route.","solutions":["Pass _class as a single string, e.g. 'contact:Person'.","To transfer multiple classes, loop client-side issuing one request per class.","Check the earlier validation errors: targetWorkspace must already be a valid string for the request to reach this check."],"exampleFix":"// before\n{ \"targetWorkspace\": \"ws-123\", \"_class\": [\"contact:Person\", \"contact:Company\"] }\n// after\n{ \"targetWorkspace\": \"ws-123\", \"_class\": \"contact:Person\" } // repeat per class","handlingStrategy":"validation","validationCode":"if (typeof body._class !== 'string' || body._class.length === 0) {\n  throw new Error('transfer requires a single string _class; loop for multiple classes')\n}","typeGuard":"function hasTransferClass(b: unknown): b is { _class: string } {\n  return typeof (b as any)?._class === 'string'\n}","tryCatchPattern":"try {\n  await transferWorkspace(payload)\n} catch (e) {\n  if (e instanceof ApiError && e.status === 400 && e.message.includes('_class')) {\n    console.error('_class must be one string, got:', payload._class)\n  }\n  throw e\n}","preventionTips":["Never pass arrays to _class; iterate classes client-side.","Use the shared model class references (model.classRefs.X) instead of hand-typed strings.","Remember validation order: targetWorkspace, then _class — fix earlier errors first when debugging."],"tags":["validation","http-400","missing-parameter","request-body"],"backgroundTag":"missing-required-parameter","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}