{"record":{"id":"94c3144791928eca","repo":"n8n-io/n8n","slug":"provider-connection-data-must-be-a-json-object","errorCode":null,"errorMessage":"Provider connection data must be a JSON object","messagePattern":"Provider connection data must be a JSON object","errorType":"exception","errorClass":"UserError","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/import/credentials.ts","lineNumber":266,"sourceCode":"\t\tif (data === undefined && credential.id) {\n\t\t\tdata = (\n\t\t\t\tawait transactionManager.findOne(CredentialsEntity, {\n\t\t\t\t\twhere: { id: credential.id },\n\t\t\t\t\tselect: { data: true },\n\t\t\t\t})\n\t\t\t)?.data;\n\t\t}\n\t\tif (data === undefined) return;\n\t\tif (data === null || data === '') {\n\t\t\tthrow new UserError('Provider connection data cannot be empty');\n\t\t}\n\n\t\tconst decrypted =\n\t\t\ttypeof data === 'string'\n\t\t\t\t? jsonParse<unknown>(await Container.get(Cipher).decryptV2(data))\n\t\t\t\t: data;\n\t\tif (!isCredentialData(decrypted)) {\n\t\t\tthrow new UserError('Provider connection data must be a JSON object');\n\t\t}\n\t\tconst credentialsService = Container.get(CredentialsService);\n\t\tif (existing?.usageScope === 'instance') {\n\t\t\tawait credentialsService.validateInstanceCredentialUpdate(\n\t\t\t\texisting,\n\t\t\t\tdecrypted,\n\t\t\t\tundefined,\n\t\t\t\tctx,\n\t\t\t);\n\t\t} else {\n\t\t\tcredentialsService.validateInstanceCredentialData(decrypted);\n\t\t}\n\t}\n\n\tprivate async checkRelations(\n\t\ttransactionManager: EntityManager,\n\t\tcredentials: Array<Pick<Partial<CredentialsEntity>, 'id'>>,\n\t\tprojectId?: string,","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/cli/src/commands/import/credentials.ts#L248-L284","documentation":"Thrown by validateInstanceCredentialData after decrypting the credential data: the decrypted payload is not a plain JSON object. isCredentialData (credentials.ts:69-70) requires `typeof === 'object'`, non-null, and not an array. So arrays, strings, numbers, booleans all fail.","triggerScenarios":"Import JSON where the (decrypted) `data` is a JSON array, a raw string, a number, or a boolean — e.g. `data: [\"a\",\"b\"]` or `data: \"key\"`. Also fires if the encrypted string decrypts to a non-object payload.","commonSituations":"Mis-formatted credential export; credential data hand-crafted as an array; encryption/decryption key mismatch producing garbage that JSON-parses to a non-object.","solutions":["Ensure the instance credential's `data` is a JSON object literal: `{ \"...\": \"...\" }`.","If using encrypted data, confirm the encryption key matches the one that encrypted it (otherwise decryption yields garbage)."],"exampleFix":"// before\n{ \"usageScope\": \"instance\", \"data\": [\"a\",\"b\"] }\n// after\n{ \"usageScope\": \"instance\", \"data\": { \"values\": [\"a\",\"b\"] } }","handlingStrategy":"type-guard","validationCode":"const isPlainObject = (v: unknown): v is Record<string, unknown> =>\n  typeof v === 'object' && v !== null && !Array.isArray(v);\n\nfunction validateInstanceCredentialData(c: Partial<CredentialsEntity>) {\n  if (c.usageScope === 'instance' && c.data !== undefined && !isPlainObject(c.data)) {\n    throw new Error('Instance credential data must be a plain JSON object');\n  }\n}\nvalidateInstanceCredentialData(credential);","typeGuard":"const isCredentialData = (data: unknown): data is Record<string, unknown> =>\n  typeof data === 'object' && data !== null && !Array.isArray(data);","tryCatchPattern":null,"preventionTips":["Format instance credential data as a JSON object literal, never an array or primitive.","When encrypting data programmatically, encrypt an object — not a stringified scalar."],"tags":["cli","import","credentials","instance-scope","validation","data","type-mismatch","user-error"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}