﻿---
title: Project scope problems
description: §§§§§§§§§§§§§§§§§§§§§§§--- navigation_title: Project scope problems applies_to: stack: unavailable serverless: preview products: id: elasticsearch, id:...
url: https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/7403/troubleshoot/elasticsearch/machine-learning/cps-datafeed-project-scope
---

# Project scope problems
§§§§§§§§§§§§§§§§§§§§§§§---
navigation_title: Project scope problems
applies_to:
stack: unavailable
serverless: preview
products:
- id: elasticsearch
- id: cloud-serverless
- id: machine-learning

---

The `project_routing` field decides which linked projects a cross-project search datafeed searches. This page covers routing that matches nothing, routing that matches too many projects, references to projects that no longer exist under an alias, and clones that inherit the source anomaly detection job's scope.

## Diagnose project scope problems

**Where to look**
- **anomaly detection job job messages in Kibana**: Open **Machine Learning → Anomaly Detection**, select the job, and review the **Job messages** tab for audit entries and warnings about linked projects, credentials, or scope changes. On the **Datafeed** tab, **View datafeed counts** opens the datafeed chart flyout for extraction timing.
  The same entries are stored in `.ml-notifications-*`.
- **`GET _ml/datafeeds/{datafeed_id}`**: Shows the effective `project_routing` value and, when an internal cloud credential exists, `authorization.cloud_api_key.id`.
- **`GET _ml/datafeeds/{datafeed_id}/_stats`**: While the datafeed runs, shows `remote_cluster_stats` with `total_clusters`, `available_clusters`, `skipped_clusters`, `availability_ratio`, `stabilized_cluster_aliases`, and `per_cluster_consecutive_skips`. The object is absent until the first search cycle establishes a baseline.
- **`.ml-annotations-*`**: Scope-change annotations for the job. The annotation `event` field carries `search_scope_changed` (not the separate `type` field).
- **`GET /_project/tags`**: Lists linked projects and their tags so you can compare them with a routing expression.
- **Elastic Cloud console**: Review linked projects in [Link and manage projects](https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/7403/deploy-manage/cross-project-search-config/cps-config-link-and-manage).

During active extraction problems, **Job messages** are authoritative. `remote_cluster_stats` from [get datafeed stats](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-datafeed-stats) reflects the last **completed** cycle.
**Check the effective scope in Kibana**
Open **Machine Learning → Anomaly Detection** and review the **Project scope** column in the anomaly detection jobs list. Each cell shows a parsed/total count (for example, `2/5`) derived from the stored routing expression and the total project count (origin plus linked projects), not from live resolution of which aliases match. Kibana parses the segment after `_alias:`: omitted or `null` routing shows `1`. `_alias:*` shows the origin-plus-linked total. A single expression such as `_alias:production-*` or `_alias:_origin` shows `1`. Because the count comes from parsing rather than resolution, a wildcard that matches several projects still shows `1`. Select the count to open a popover titled **Project scope** that displays the routing expression stored on the datafeed. A legacy anomaly detection job with no stored routing shows `_alias:_origin` in the popover.
**Error messages: routing matches no project**
During create, update, or extraction, **Job messages** or the API can report one of these machine learning-enriched errors:
On create or update (validate-before-mint):
Create failures use the same *Cannot update datafeed* wording even though the request is a put.
```txt
Cannot update datafeed [my-datafeed]: project_routing [_alias:nonexistent-*] matched no linked project (no matching project after applying project routing [_alias:nonexistent-*]). Link the missing project in Elastic Cloud project settings, or update project_routing to a valid linked alias (for example _origin for local-only scope).
```

During extraction or preview:
```txt
Datafeed [my-datafeed] cannot search any project: project_routing [_alias:nonexistent-*] matched no linked projects at run time (no matching project after applying project routing [_alias:nonexistent-*]). Link the missing project(s) in Elastic Cloud project settings, or update project_routing to an expression that matches at least one linked project (for example _origin for local-only scope).
```

The bracketed datafeed id, routing expression, and parenthesised cause vary with your configuration. The parenthesised text comes from Elasticsearch itself, typically in one of these forms:
```txt
no matching project after applying project routing [_alias:nonexistent-*]
```

```txt
No such project: [missing-project] with project routing [_alias:production-*]
```

The suggested `_origin` example in the machine learning messages is not a valid routing value. Use `_alias:_origin` for origin-project-only scope instead. See [Project routing in CPS](https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/7403/explore-analyze/cross-project-search/cross-project-search-project-routing).
**When each failure happens**

| Situation                                                                                                               | Typical behavior                                              |
|-------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------|
| Flat-world datafeed (empty `project_routing`, unqualified index patterns) with no linked projects                       | Create or update can succeed. The first run-time search fails |
| Flat-world datafeed (unqualified index patterns) with `_alias:` expression that matches no linked tags, including typos | Create or update can succeed. The first run-time search fails |
| datafeed with qualified `project:index` patterns and `project_routing` that matches no linked tags                      | Fails immediately on create or update (validate-before-mint)  |
| Qualified `project:index` references a project that does not exist or is unauthorized                                   | Fails immediately on create or update                         |

Validate-before-mint defers a no-match `project_routing` to run time only when every entry in `indices` is unqualified (flat-world). Any qualified `project:index` pattern, including one whose project alias is missing, fails immediately on create or update.
**Scope is wider than intended**
- datafeed extraction cycles take noticeably longer after new projects were linked.
- `GET _ml/datafeeds/{datafeed_id}/_stats` shows `remote_cluster_stats` fanning out to many linked projects you do not need.
- `project_routing` is empty, omitted, or uses a wide expression such as `_alias:*` that matches most linked aliases.
- The anomaly detection job was created without an explicit routing expression and now searches all linked projects by default.

**Stale project reference**
- **Job messages** or extraction errors reference a project alias that no longer appears in `GET /_project/tags` or the Cloud console linked-project list.
- `project_routing` still contains an `_alias:` tag that matched a project before it was renamed or unlinked.
- A qualified index pattern such as `old-alias:logs-*` names a project alias that is no longer linked.

**Cloned job searches unexpected projects**
- A cloned anomaly detection job searches more linked projects than intended.
- `GET _ml/datafeeds/{datafeed_id}` on the clone shows the same `project_routing` as the source datafeed.
- Cloning reuses the job-creation wizard, which copies the source datafeed configuration (including `project_routing`) into the new job before you confirm create.


## Resolve project scope problems

Stop the datafeed before updating it. If the datafeed is still running, the update fails with:
```txt
Cannot update datafeed [my-datafeed] while its status is started
```

The bracketed datafeed id and status vary with your configuration.
When a `project_routing` update changes the effective search scope, Elasticsearch retains the job's current model snapshot as a rollback point before applying the change. By default, that rollback gate requires the anomaly detection job to be closed. If the job is still open, the update fails with:
```txt
Cannot update project_routing for datafeed [my-datafeed] while job [my-job] is opened. Close the job so a rollback model snapshot can be retained.
```

The bracketed datafeed id, job id, and job state vary with your configuration.
The rollback gate also requires an existing model snapshot. If the job has never produced one, the update fails with:
```txt
Cannot update project_routing for datafeed [my-datafeed] because job [my-job] has no model snapshot to use as a rollback point. Open the job, ingest data, then close it before changing scope.
```

A job that has never run has no snapshot. Open it, let it process data, then close it before changing project scope.
Elasticsearch records the retained rollback snapshot in the job's **Job messages** (or `.ml-notifications-*`), for example:
```txt
Rollback model snapshot [1720000000] retained before project_routing scope change: Automatic rollback snapshot retained before project_routing scope change [] -> [_alias:prod-*]
```

When the datafeed already had a stored routing value, the bracketed pair shows the old and new expressions instead of an empty left side:
```txt
Rollback model snapshot [1720000000] retained before project_routing scope change: Automatic rollback snapshot retained before project_routing scope change [_alias:_origin] -> [_alias:prod-*]
```

You can revert to that snapshot if detection quality degrades after a scope change.
Exception: assigning `_alias:_origin` for the first time to a datafeed that had no `project_routing` preserves the existing local-only scope. That update bypasses the rollback gate entirely. Neither the closed-job check nor the snapshot requirement applies.
**Correct the routing expression**
Update routing to a valid `_alias:` expression:
```json

{
  "project_routing": "_alias:production-*"
}
```

**Narrow to the origin project**
When you only need data from the local project, set origin-project-only routing:
```json

{
  "project_routing": "_alias:_origin"
}
```

**Link a missing project**
If routing references a project that should be in scope, establish the link in [Link and manage projects](https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/7403/deploy-manage/cross-project-search-config/cps-config-link-and-manage), then update routing or wait for the next extraction cycle.
**Fix a stale qualified index**
When `indices` contains a qualified `project:index` pattern, update both `project_routing` and the qualified index reference after a rename or unlink:
```json

{
  "project_routing": "_alias:production-*",
  "indices": ["new-alias:logs-*"]
}
```

Changing `indices` also changes the cross-project search surface, which can re-key the internal cloud credential. See [Cloud credential problems](https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/7403/troubleshoot/elasticsearch/machine-learning/cps-datafeed-credentials).
**Set scope when creating or cloning a job**
When creating or cloning a job in Kibana, set **Project scope** before you finish the wizard:
- On **Select data view or saved Discover session**, use the **Project scope** control to pick routing before you choose the data source.
- On later wizard steps (including the datafeed step), the **Project scope** section shows the label **Project scope** with the description *Select the project routing for the job.* Adjust routing there if the clone inherited a broader scope than you need.

**Verify**
Confirm recovery in three places:
- The **Project scope** column shows the intended parsed/total count and popover expression.
- `GET _ml/datafeeds/{datafeed_id}` returns the expected `project_routing` value.
- `GET _ml/datafeeds/{datafeed_id}/_stats` shows successful extraction cycles and `remote_cluster_stats` listing only the intended projects.