{"record":{"id":"65860ab55d855181","repo":"n8n-io/n8n","slug":"column-virtualcolumn-propertyname-of-entity","errorCode":null,"errorMessage":"Column \"${virtualColumn.propertyName}\" of Entity \"${entityMetadata.name}\" is defined as VIRTUAL, but Postgres supports only STORED generated columns.","messagePattern":"Column \"(.+?)\" of Entity \"(.+?)\" is defined as VIRTUAL, but Postgres supports only STORED generated columns\\.","errorType":"exception","errorClass":"TypeORMError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/typeorm/src/metadata-builder/EntityMetadataValidator.ts","lineNumber":132,"sourceCode":"\t\t\t\t\tthrow new DataTypeNotSupportedError(column, normalizedColumn, driver.options.type);\n\t\t\t\tif (column.length && driver.withLengthColumnTypes.indexOf(normalizedColumn) === -1)\n\t\t\t\t\tthrow new TypeORMError(\n\t\t\t\t\t\t`Column ${column.propertyName} of Entity ${entityMetadata.name} does not support length property.`,\n\t\t\t\t\t);\n\t\t\t\tif (column.type === 'enum' && !column.enum && !column.enumName)\n\t\t\t\t\tthrow new TypeORMError(\n\t\t\t\t\t\t`Column \"${column.propertyName}\" of Entity \"${entityMetadata.name}\" is defined as enum, but missing \"enum\" or \"enumName\" properties.`,\n\t\t\t\t\t);\n\t\t\t});\n\n\t\t// Postgres supports only STORED generated columns.\n\t\tif (driver.options.type === 'postgres') {\n\t\t\tconst virtualColumn = entityMetadata.columns.find(\n\t\t\t\t(column) =>\n\t\t\t\t\tcolumn.asExpression && (!column.generatedType || column.generatedType === 'VIRTUAL'),\n\t\t\t);\n\t\t\tif (virtualColumn)\n\t\t\t\tthrow new TypeORMError(\n\t\t\t\t\t`Column \"${virtualColumn.propertyName}\" of Entity \"${entityMetadata.name}\" is defined as VIRTUAL, but Postgres supports only STORED generated columns.`,\n\t\t\t\t);\n\t\t}\n\n\t\t// check if relations are all without initialized properties\n\t\tconst entityInstance = entityMetadata.create(undefined, {\n\t\t\tfromDeserializer: true,\n\t\t});\n\t\tentityMetadata.relations.forEach((relation) => {\n\t\t\tif (relation.isManyToMany || relation.isOneToMany) {\n\t\t\t\t// we skip relations for which persistence is disabled since initialization in them cannot harm somehow\n\t\t\t\tif (relation.persistenceEnabled === false) return;\n\n\t\t\t\t// get entity relation value and check if its an array\n\t\t\t\tconst relationInitializedValue = relation.getEntityValue(entityInstance);\n\t\t\t\tif (Array.isArray(relationInitializedValue)) throw new InitializedRelationError(relation);\n\t\t\t}\n\t\t});","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/typeorm/src/metadata-builder/EntityMetadataValidator.ts#L114-L150","documentation":"Thrown by EntityMetadataValidator.validate in the postgres-only branch when any column has asExpression set (i.e. it is a generated column) and generatedType is either unset or 'VIRTUAL'. Postgres supports only STORED generated columns, so a virtual generated column fails validation.","triggerScenarios":"Declaring a generated column with @Column({ type: 'generated', asExpression: '...', generatedType: 'VIRTUAL' }) (or omitting generatedType) on a postgres DataSource.","commonSituations":"Sharing entity definitions between MySQL (which supports VIRTUAL) and postgres; defaulting generatedType and assuming it stays STORED; copying a generated-column example written for MySQL.","solutions":["Set generatedType: 'STORED' on the generated column when targeting postgres.","If the column truly must be virtual, choose a different database (postgres will reject it).","Drop the asExpression option if the column is not actually generated."],"exampleFix":"// before\n@Column({\n  type: 'generated',\n  asExpression: 'lower(name)',\n  generatedType: 'VIRTUAL',\n})\nnameLower: string;\n\n// after (postgres)\n@Column({\n  type: 'generated',\n  asExpression: 'lower(name)',\n  generatedType: 'STORED',\n})\nnameLower: string;","handlingStrategy":"validation","validationCode":"function assertNoVirtualGeneratedOnPostgres(dataSource: DataSource): string[] {\n  if (dataSource.options.type !== 'postgres') return [];\n  const problems: string[] = [];\n  for (const meta of dataSource.entityMetadatas) {\n    for (const col of meta.columns) {\n      if (col.asExpression && (!col.generatedType || col.generatedType === 'VIRTUAL')) {\n        problems.push(`${meta.targetName}.${col.propertyName} is VIRTUAL generated; postgres needs STORED`);\n      }\n    }\n  }\n  return problems;\n}","typeGuard":null,"tryCatchPattern":"try {\n  await dataSource.initialize();\n} catch (err) {\n  if (err.message.includes('VIRTUAL, but Postgres supports only STORED')) {\n    // change generatedType to 'STORED'\n  }\n  throw err;\n}","preventionTips":["Default generatedType to 'STORED' on shared entities used across MySQL and postgres.","Run the post-init generated-column validator in CI for the postgres target.","Document that virtual generated columns are MySQL-only in the project's data-modelling guide."],"tags":["postgres","generated-column","virtual","startup"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}