# Firestore: “Invalid document reference” (even number of segments)

> Firestore threw invalid document reference: the path has an odd number of segments. Check for an empty id, a slash in the id or a collection path in doc().

Canonical: https://app369.com/fix/firestore-invalid-document-reference/
Last updated: 2026-11-09

Invalid document reference is the Firestore error for a doc() path with an odd number of segments. A document path alternates collection and document, like users/abc, so it always has an even count. The usual cause is an empty id or a slash inside one.

**Short answer**

Log the path you pass to doc(). If an id is empty or undefined, wait until it exists. If an id contains a slash, such as a URL or a date, encode it or pick another id. Use collection() for paths with an odd number of segments, like users/abc/orders.

Rather not fix it yourself? [**App Fix Ticket**](https://app369.com/fixed-price/flutter-firebase-bug-fix/) starts with a fixed-price diagnosis, then a fixed price for the fix before any fix work.

## **What breaks the path, and the fix**

1. 01 ### **The id is an empty string**
  > “If the final path has an odd number of segments and does not point to a document.” [**Firebase, doc() exceptions**](https://firebase.google.com/docs/reference/js/firestore_.md) An empty uid makes doc(db, 'users', uid) a one-segment path, so it throws this error. An undefined uid throws a different error, and a template string such as users/${uid} builds users/undefined: a valid path to the wrong document, with no error at all. Wait for sign-in before you build the path, and throw a clear error if the id is missing.```
// Web SDK
import { doc, getDoc } from 'firebase/firestore';

if (!uid) throw new Error('No user id yet');
const snap = await getDoc(doc(db, 'users', uid));
```
2. 02 ### **The id contains a slash** Each slash starts a new segment, so an id like 2026/11/09 or a full URL splits into several, and a double slash in a built path fails too. Encode the value, or use a hash of it for long values. Don’t just swap slashes for another character: two different values can end up with the same id, and setDoc then overwrites one with the other.```
const id = encodeURIComponent(url); // reversible, so no two urls share an id
await setDoc(doc(db, 'links', id), { url });
```
3. 03 ### **A collection path went into doc()**
  > “Notice the alternating pattern of collections and documents. Your collections and documents must always follow this pattern.” [**Firebase, Cloud Firestore data model**](https://firebase.google.com/docs/firestore/data-model) users/abc/orders points to a subcollection, which has three segments. Use collection() for it, and doc() for a document such as users/abc/orders/o1.```
const orders = collection(db, 'users', uid, 'orders'); // 3 segments
const order = doc(db, 'users', uid, 'orders', orderId); // 4 segments
```
4. 04 ### **The same mistake the other way round**
  > “If the final path has an even number of segments and does not point to a collection.” [**Firebase, collection() exceptions**](https://firebase.google.com/docs/reference/js/firestore_.md) collection() with a document path, such as users/abc, throws the matching error about an even number of segments. Drop the last segment or switch to doc().
5. 05 ### **A document can’t sit inside a document**
  > “You cannot reference a collection in a collection or a document in a document.” [**Firebase, Cloud Firestore data model**](https://firebase.google.com/docs/firestore/data-model) Data nested under a document goes in a field or in a subcollection, never straight under another document. If the path was built for nesting, put a collection name between the two ids.

Checked against the vendor’s docs on November 9, 2026: [Firebase docs: Cloud Firestore data model](https://firebase.google.com/docs/firestore/data-model); [Firebase JS SDK reference: firestore](https://firebase.google.com/docs/reference/js/firestore_.md).

## **Rather hand it over?**

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

- [from $450**App Fix Ticket**One reproducible bug in an existing mobile or web app, diagnosed and fixed.**See scope and start**](https://app369.com/fixed-price/flutter-firebase-bug-fix/)
- [from $450**AI-Built App Rescue**A Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.****No issues worth fixing, no charge.**** If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.**See scope and start**](https://app369.com/fixed-price/ai-app-rescue/)

[**All 127 Fiverr reviews**](https://app369.com/reviews/)

Related: [**Firestore unsupported field value: undefined**](https://app369.com/fix/firestore-unsupported-field-value-undefined/) · [**Firebase missing or insufficient permissions**](https://app369.com/fix/firebase-missing-or-insufficient-permissions/) · [**Firestore client is offline**](https://app369.com/fix/firestore-client-is-offline/) · [**Firestore ALREADY_EXISTS**](https://app369.com/fix/firestore-already-exists-document/)

Questions

## **More on this error**

<details>

<summary>**Does the Admin SDK throw the same error? **+</summary>

The Admin SDK also checks the path, with its own wording. There the call is db.collection('users').doc(uid) or db.doc('users/' + uid), and the same fixes apply: no empty ids, no slashes inside ids, and doc() only for document paths.

</details>

<details>

<summary>**Can I use a slash in a document id at all? **+</summary>

No. A slash always splits the path. Encode the value or store it in a field, and use another value as the id.

</details>

<details>

<summary>**Can you fix it for me? **+</summary>

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

</details>

A different error?

## **Describe it and get a written quote**

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.

[**Describe your problem **→](https://app369.com/contact/) [**All fixes**](https://app369.com/fix/)