diff --git a/lib/modules/manager/poetry/__fixtures__/pyproject.2.toml b/lib/modules/manager/poetry/__fixtures__/pyproject.2.toml
index 615286f223408be814aaf83420ab02dbe227e22e..d48aebadf8db08750ca7ef77ad65e1c59fa5e6a6 100644
--- a/lib/modules/manager/poetry/__fixtures__/pyproject.2.toml
+++ b/lib/modules/manager/poetry/__fixtures__/pyproject.2.toml
@@ -9,6 +9,7 @@ dep1 = { version =  "*" }
 dep2 = { version = "^0.6.0" }
 dep3 = { path = "/some/path/", version = '^0.33.6' }
 dep4 = { path = "/some/path/" }
+dep5 = {}
 
 [tool.poetry.extras]
 extra_dep1 = "^0.8.3"
diff --git a/lib/modules/manager/poetry/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/poetry/__snapshots__/extract.spec.ts.snap
index 4265b8669acacc8ed2dc45a2f1cb5aad5a985360..f6ece0f45b9362f27f45f5c17074443eac09c824 100644
--- a/lib/modules/manager/poetry/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/poetry/__snapshots__/extract.spec.ts.snap
@@ -392,6 +392,16 @@ exports[`modules/manager/poetry/extract extractPackageFile() extracts multiple d
       },
       "skipReason": "path-dependency",
     },
+    {
+      "currentValue": "",
+      "datasource": "pypi",
+      "depName": "dep5",
+      "depType": "dependencies",
+      "managerData": {
+        "nestedVersion": false,
+      },
+      "versioning": "pep440",
+    },
     {
       "currentValue": "^0.8.3",
       "datasource": "pypi",
diff --git a/lib/modules/manager/poetry/extract.spec.ts b/lib/modules/manager/poetry/extract.spec.ts
index 56fca72715c412e950e8b3d881b09074666cb1f9..dc2738e8edb89e7af5c0bbf78ead4139f205d9c3 100644
--- a/lib/modules/manager/poetry/extract.spec.ts
+++ b/lib/modules/manager/poetry/extract.spec.ts
@@ -57,7 +57,7 @@ describe('modules/manager/poetry/extract', () => {
     it('extracts multiple dependencies (with dep = {version = "1.2.3"} case)', async () => {
       const res = await extractPackageFile(pyproject2toml, filename);
       expect(res).toMatchSnapshot();
-      expect(res?.deps).toHaveLength(7);
+      expect(res?.deps).toHaveLength(8);
     });
 
     it('handles case with no dependencies', async () => {
diff --git a/lib/modules/manager/poetry/extract.ts b/lib/modules/manager/poetry/extract.ts
index 86e1a70227bb163428a57cf2c1c6be8633903c7c..c69d3e0d29620ef129af7496d4a349a32e230eb2 100644
--- a/lib/modules/manager/poetry/extract.ts
+++ b/lib/modules/manager/poetry/extract.ts
@@ -1,4 +1,3 @@
-import { parse } from '@iarna/toml';
 import is from '@sindresorhus/is';
 import { logger } from '../../../logger';
 import type { SkipReason } from '../../../types';
@@ -15,34 +14,50 @@ import * as pep440Versioning from '../../versioning/pep440';
 import * as poetryVersioning from '../../versioning/poetry';
 import type { PackageDependency, PackageFileContent } from '../types';
 import { extractLockFileEntries } from './locked-version';
-import type { PoetryDependency, PoetryFile, PoetrySection } from './types';
+import type {
+  PoetryDependencyRecord,
+  PoetryGroupRecord,
+  PoetrySchema,
+  PoetrySectionSchema,
+} from './schema';
+import { parsePoetry } from './utils';
 
 function extractFromDependenciesSection(
-  parsedFile: PoetryFile,
-  section: keyof Omit<PoetrySection, 'source' | 'group'>,
+  parsedFile: PoetrySchema,
+  section: keyof Omit<PoetrySectionSchema, 'source' | 'group'>,
   poetryLockfile: Record<string, string>
 ): PackageDependency[] {
   return extractFromSection(
-    parsedFile.tool?.poetry?.[section],
+    parsedFile?.tool?.poetry?.[section],
     section,
     poetryLockfile
   );
 }
 
 function extractFromDependenciesGroupSection(
-  parsedFile: PoetryFile,
-  group: string,
+  groupSections: PoetryGroupRecord | undefined,
   poetryLockfile: Record<string, string>
 ): PackageDependency[] {
-  return extractFromSection(
-    parsedFile.tool?.poetry?.group[group]?.dependencies,
-    group,
-    poetryLockfile
-  );
+  if (!groupSections) {
+    return [];
+  }
+
+  const deps = [];
+  for (const groupName of Object.keys(groupSections)) {
+    deps.push(
+      ...extractFromSection(
+        groupSections[groupName]?.dependencies,
+        groupName,
+        poetryLockfile
+      )
+    );
+  }
+
+  return deps;
 }
 
 function extractFromSection(
-  sectionContent: Record<string, PoetryDependency | string> | undefined,
+  sectionContent: PoetryDependencyRecord | undefined,
   depType: string,
   poetryLockfile: Record<string, string>
 ): PackageDependency[] {
@@ -68,35 +83,39 @@ function extractFromSection(
       lockedVersion = poetryLockfile[packageName];
     }
     if (!is.string(currentValue)) {
-      const version = currentValue.version;
-      const path = currentValue.path;
-      const git = currentValue.git;
-      if (version) {
-        currentValue = version;
-        nestedVersion = true;
-        if (!!path || git) {
-          skipReason = path ? 'path-dependency' : 'git-dependency';
-        }
-      } else if (path) {
+      if (is.array(currentValue)) {
         currentValue = '';
-        skipReason = 'path-dependency';
-      } else if (git) {
-        if (currentValue.tag) {
-          currentValue = currentValue.tag;
-          datasource = GithubTagsDatasource.id;
-          const githubPackageName = extractGithubPackageName(git);
-          if (githubPackageName) {
-            packageName = githubPackageName;
+        skipReason = 'multiple-constraint-dep';
+      } else {
+        const version = currentValue.version;
+        const path = currentValue.path;
+        const git = currentValue.git;
+        if (version) {
+          currentValue = version;
+          nestedVersion = true;
+          if (!!path || git) {
+            skipReason = path ? 'path-dependency' : 'git-dependency';
+          }
+        } else if (path) {
+          currentValue = '';
+          skipReason = 'path-dependency';
+        } else if (git) {
+          if (currentValue.tag) {
+            currentValue = currentValue.tag;
+            datasource = GithubTagsDatasource.id;
+            const githubPackageName = extractGithubPackageName(git);
+            if (githubPackageName) {
+              packageName = githubPackageName;
+            } else {
+              skipReason = 'git-dependency';
+            }
           } else {
+            currentValue = '';
             skipReason = 'git-dependency';
           }
         } else {
           currentValue = '';
-          skipReason = 'git-dependency';
         }
-      } else {
-        currentValue = '';
-        skipReason = 'multiple-constraint-dep';
       }
     }
     const dep: PackageDependency = {
@@ -126,8 +145,8 @@ function extractFromSection(
   return deps;
 }
 
-function extractRegistries(pyprojectfile: PoetryFile): string[] | undefined {
-  const sources = pyprojectfile.tool?.poetry?.source;
+function extractRegistries(pyprojectfile: PoetrySchema): string[] | undefined {
+  const sources = pyprojectfile?.tool?.poetry?.source;
 
   if (!Array.isArray(sources) || sources.length === 0) {
     return undefined;
@@ -149,14 +168,8 @@ export async function extractPackageFile(
   packageFile: string
 ): Promise<PackageFileContent | null> {
   logger.trace(`poetry.extractPackageFile(${packageFile})`);
-  let pyprojectfile: PoetryFile;
-  try {
-    pyprojectfile = parse(content);
-  } catch (err) {
-    logger.debug({ err, packageFile }, 'Error parsing pyproject.toml file');
-    return null;
-  }
-  if (!pyprojectfile.tool?.poetry) {
+  const pyprojectfile = parsePoetry(packageFile, content);
+  if (!pyprojectfile?.tool?.poetry) {
     logger.debug({ packageFile }, `contains no poetry section`);
     return null;
   }
@@ -180,8 +193,9 @@ export async function extractPackageFile(
       lockfileMapping
     ),
     ...extractFromDependenciesSection(pyprojectfile, 'extras', lockfileMapping),
-    ...Object.keys(pyprojectfile.tool?.poetry?.group ?? []).flatMap((group) =>
-      extractFromDependenciesGroupSection(pyprojectfile, group, lockfileMapping)
+    ...extractFromDependenciesGroupSection(
+      pyprojectfile?.tool?.poetry?.group,
+      lockfileMapping
     ),
   ];
 
@@ -191,9 +205,9 @@ export async function extractPackageFile(
 
   const extractedConstraints: Record<string, any> = {};
 
-  if (is.nonEmptyString(pyprojectfile.tool?.poetry?.dependencies?.python)) {
+  if (is.nonEmptyString(pyprojectfile?.tool?.poetry?.dependencies?.python)) {
     extractedConstraints.python =
-      pyprojectfile.tool?.poetry?.dependencies?.python;
+      pyprojectfile?.tool?.poetry?.dependencies?.python;
   }
 
   const res: PackageFileContent = {
diff --git a/lib/modules/manager/poetry/schema.ts b/lib/modules/manager/poetry/schema.ts
new file mode 100644
index 0000000000000000000000000000000000000000..56f419739fd4fbc8efe8750e0b0fc96a29fa9967
--- /dev/null
+++ b/lib/modules/manager/poetry/schema.ts
@@ -0,0 +1,55 @@
+import { z } from 'zod';
+import { LooseRecord, Toml } from '../../../util/schema-utils';
+
+const PoetryDependencySchema = z.object({
+  path: z.string().optional(),
+  git: z.string().optional(),
+  tag: z.string().optional(),
+  version: z.string().optional(),
+});
+
+export const PoetryDependencyRecord = LooseRecord(
+  z.string(),
+  z.union([PoetryDependencySchema, z.array(PoetryDependencySchema), z.string()])
+);
+
+export type PoetryDependencyRecord = z.infer<typeof PoetryDependencyRecord>;
+
+export const PoetryGroupRecord = LooseRecord(
+  z.string(),
+  z.object({
+    dependencies: PoetryDependencyRecord.optional(),
+  })
+);
+
+export type PoetryGroupRecord = z.infer<typeof PoetryGroupRecord>;
+
+export const PoetrySectionSchema = z.object({
+  dependencies: PoetryDependencyRecord.optional(),
+  'dev-dependencies': PoetryDependencyRecord.optional(),
+  extras: PoetryDependencyRecord.optional(),
+  group: PoetryGroupRecord.optional(),
+  source: z
+    .array(z.object({ name: z.string(), url: z.string().optional() }))
+    .optional(),
+});
+
+export type PoetrySectionSchema = z.infer<typeof PoetrySectionSchema>;
+
+export const PoetrySchema = z.object({
+  tool: z
+    .object({
+      poetry: PoetrySectionSchema.optional(),
+    })
+    .optional(),
+  'build-system': z
+    .object({
+      requires: z.array(z.string()),
+      'build-backend': z.string().optional(),
+    })
+    .optional(),
+});
+
+export type PoetrySchema = z.infer<typeof PoetrySchema>;
+
+export const PoetrySchemaToml = Toml.pipe(PoetrySchema);
diff --git a/lib/modules/manager/poetry/utils.spec.ts b/lib/modules/manager/poetry/utils.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d3ba582378d0b1568251654da461d4f83776fe98
--- /dev/null
+++ b/lib/modules/manager/poetry/utils.spec.ts
@@ -0,0 +1,40 @@
+import { codeBlock } from 'common-tags';
+import { parsePoetry } from './utils';
+
+describe('modules/manager/poetry/utils', () => {
+  const fileName = 'fileName';
+
+  describe('parsePoetry', () => {
+    it('load and parse successfully', () => {
+      const fileContent = codeBlock`
+        [tool.poetry.dependencies]
+        dep1 = "1.0.0"
+        [tool.poetry.group.dev.dependencies]
+        dep2 = "1.0.1"
+      `;
+      const actual = parsePoetry(fileName, fileContent);
+      expect(actual).toMatchObject({
+        tool: {
+          poetry: {
+            dependencies: { dep1: '1.0.0' },
+            group: { dev: { dependencies: { dep2: '1.0.1' } } },
+          },
+        },
+      });
+    });
+
+    it('invalid toml', () => {
+      const actual = parsePoetry(fileName, 'clearly_invalid');
+      expect(actual).toBeNull();
+    });
+
+    it('invalid schema', () => {
+      const fileContent = codeBlock`
+        [tool.poetry.dependencies]:
+        dep1 = 1
+      `;
+      const actual = parsePoetry(fileName, fileContent);
+      expect(actual).toBeNull();
+    });
+  });
+});
diff --git a/lib/modules/manager/poetry/utils.ts b/lib/modules/manager/poetry/utils.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3ec55cef790bfeecf41149bd1bee62a8377f4e5f
--- /dev/null
+++ b/lib/modules/manager/poetry/utils.ts
@@ -0,0 +1,14 @@
+import { logger } from '../../../logger';
+import { type PoetrySchema, PoetrySchemaToml } from './schema';
+
+export function parsePoetry(
+  fileName: string,
+  fileContent: string
+): PoetrySchema | null {
+  const res = PoetrySchemaToml.safeParse(fileContent);
+  if (res.success) {
+    return res.data;
+  }
+  logger.debug({ err: res.error, fileName }, 'Error parsing poetry lockfile.');
+  return null;
+}