diff --git a/src/Scaffolding/PostgresReflector.php b/src/Scaffolding/PostgresReflector.php
index 9496d410d816ccd4e7ecc42ac3fef9cfdfdf13d2..da2d552bc28382783960da100453d7c2b3c6ced9 100644
--- a/src/Scaffolding/PostgresReflector.php
+++ b/src/Scaffolding/PostgresReflector.php
@@ -6,6 +6,7 @@ namespace Grifart\Tables\Scaffolding;
 
 use Dibi\Connection;
 use Grifart\Tables\ColumnMetadata;
+use Grifart\Tables\MissingPrimaryIndex;
 use function Functional\map;
 use function Functional\reindex;
 
@@ -75,6 +76,10 @@ WHERE pg_index.indisprimary AND pg_namespace.nspname = %s AND pg_class.relname =
 SQL
 			, $schema, $table)->setType('indkey', null)->fetchSingle();
 
+		if ($rawPrimaryKeyColumnPositions === null) {
+			throw MissingPrimaryIndex::in($schema, $table);
+		}
+
 		$primaryKeyColumnPositions = \explode(' ', $rawPrimaryKeyColumnPositions);
 		return reindex(
 			map(
diff --git a/src/exceptions.php b/src/exceptions.php
index cab513bb3cd16e9ded21c6ce5be17436f8164b00..b209bea166059deed76cce8d4aa037e849cf68c0 100644
--- a/src/exceptions.php
+++ b/src/exceptions.php
@@ -5,6 +5,14 @@ namespace Grifart\Tables;
 abstract class UsageException extends \LogicException {}
 abstract class RuntimeException extends \RuntimeException {}
 
+final class MissingPrimaryIndex extends UsageException
+{
+	public static function in(string $schema, string $table): self
+	{
+		return new self(\sprintf('Table "%s"."%s" must have a primary index. Provide one and try again.', $schema, $table));
+	}
+}
+
 final class ProbablyBrokenPrimaryIndexImplementation extends UsageException {
 	public function __construct(Table $table, int $affectedRows)
 	{
diff --git a/tests/Fixtures/.definition.missingPrimaryIndex.php b/tests/Fixtures/.definition.missingPrimaryIndex.php
new file mode 100644
index 0000000000000000000000000000000000000000..b909be3cf3965a6eb5f7c98d66318d3501ede231
--- /dev/null
+++ b/tests/Fixtures/.definition.missingPrimaryIndex.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Grifart\Tables\Tests\Fixtures;
+
+use Dibi\Connection;
+use Grifart\Tables\Database\Identifier;
+use Grifart\Tables\Scaffolding\PostgresReflector;
+use Grifart\Tables\Scaffolding\TablesDefinitions;
+use Grifart\Tables\TypeResolver;
+use Grifart\Tables\Types\TextType;
+
+
+$connection = require __DIR__ . '/../createConnection.local.php';
+\assert($connection instanceof Connection);
+
+$reflector = new PostgresReflector($connection);
+$typeResolver = (new TypeResolver($connection));
+$typeResolver->addResolutionByLocation(new Identifier('public', 'missingPrimaryIndex', 'whatever'), TextType::text());
+$tableDefinitions = new TablesDefinitions($reflector, $typeResolver);
+
+return [
+	...$tableDefinitions->for(
+		'public',
+		'missingPrimaryIndex',
+		MissingPrimaryIndexRow::class,
+		MissingPrimaryIndexModifications::class,
+		MissingPrimaryIndexTable::class,
+		MissingPrimaryIndexPrimaryKey::class,
+	)
+];
diff --git a/tests/Scaffolding/ScaffoldingTest.missingPrimaryIndex.phpt b/tests/Scaffolding/ScaffoldingTest.missingPrimaryIndex.phpt
new file mode 100644
index 0000000000000000000000000000000000000000..b7ac41c9e7bad984dac8206f47809c5a62f93d29
--- /dev/null
+++ b/tests/Scaffolding/ScaffoldingTest.missingPrimaryIndex.phpt
@@ -0,0 +1,25 @@
+<?php declare(strict_types = 1);
+
+namespace Grifart\Tables\Tests\Scaffolding;
+
+use Grifart\ClassScaffolder\Definition\ClassDefinition;
+use Grifart\ClassScaffolder\DefinitionFile;
+use Grifart\ClassScaffolder\DefinitionResult;
+use Grifart\ClassScaffolder\FileProcessor;
+use Tester\Assert;
+use function Grifart\Tables\Tests\connect;
+
+
+require __DIR__ . '/../bootstrap.php';
+
+connect();
+
+$fileProcessor = new FileProcessor();
+
+$results = $fileProcessor->processFile(
+	DefinitionFile::from(__DIR__ . '/../Fixtures/.definition.missingPrimaryIndex.php'),
+	static fn(ClassDefinition $definition) => DefinitionResult::success($definition), // won't be called but has to return something
+);
+
+Assert::true( ! $results->isSuccessful());
+Assert::same('Table "public"."missingPrimaryIndex" must have a primary index. Provide one and try again.', $results->getError()->getMessage());
diff --git a/tests/initializeDatabase.php b/tests/initializeDatabase.php
index 68d13a296139d9d19d2ce60fe559649d629c9fb4..f1094c2b8425a6c6f656010038a83daabdd5395a 100644
--- a/tests/initializeDatabase.php
+++ b/tests/initializeDatabase.php
@@ -33,3 +33,9 @@ CREATE TABLE IF NOT EXISTS public.package (
     "previousVersions" public."packageVersion"[] NOT NULL
 );
 SQL);
+
+$connection->nativeQuery(<<<SQL
+CREATE TABLE IF NOT EXISTS public."missingPrimaryIndex" (
+    whatever text NOT NULL
+);
+SQL);