# Troubleshooting

> Diagnose and fix common Cartography intel-module errors — `ModuleNotFoundError`, `PropertyRef validation failed`, `GraphJob failed`, missing relationships, MatchLink misses, cleanup deleting too much, slow queries, ignored custom schema fields, key errors during transform. Use when the user reports an error while developing or running a Cartography module.

- Skill: `cartography-cncf/troubleshooting` (Agent Skill)
- Install (CLI): `npx skillmds@latest add cartography-cncf/troubleshooting`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cartography-cncf/troubleshooting/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: cartography-cncf (https://skillmd.com/u/cartography-cncf)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/cartography-cncf/troubleshooting

---


# troubleshooting

Diagnostic playbook for the most common errors encountered while developing Cartography intel modules.

## Common issues and solutions

### Import errors

```python
# Problem: ModuleNotFoundError for your new module
# Solution: ensure __init__.py files exist in all directories
cartography/intel/your_service/__init__.py
cartography/models/your_service/__init__.py
```

Checklist:

- [ ] `__init__.py` exists in `cartography/intel/your_service/`
- [ ] `__init__.py` exists in `cartography/models/your_service/`
- [ ] Module is imported in the parent `__init__.py` if needed

### Schema validation errors

```python
# Problem: "PropertyRef validation failed"
# Solution: check dataclass syntax and PropertyRef definitions
@dataclass(frozen=True)  # do not forget frozen=True
class YourNodeProperties(CartographyNodeProperties):
    id: PropertyRef = PropertyRef("id")  # must have type annotation
    lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
```

Common causes:

- Missing `frozen=True` in `@dataclass`.
- Missing type annotation (`: PropertyRef`).
- Typo in the `PropertyRef` field name.

### Relationship connection issues

```python
# Problem: relationships not created
# Solution: ensure target nodes exist before creating relationships

# Load parent nodes first:
load(neo4j_session, TenantSchema(), tenant_data, lastupdated=update_tag)

# Then load child nodes with relationships:
load(neo4j_session, UserSchema(), user_data, lastupdated=update_tag, TENANT_ID=tenant_id)
```

Debugging steps:

1. Check the target node label matches exactly.
2. Verify `target_node_matcher` keys match the **target node's** property names.
3. Ensure the value in your data dict or kwargs is not `None`.

### Cleanup job failures

```python
# Problem: "GraphJob failed" during cleanup
# Solution: check common_job_parameters
common_job_parameters = {
    "UPDATE_TAG": config.update_tag,  # must match what is set on nodes
    "TENANT_ID": tenant_id,           # if using scoped cleanup (default)
}
```

```python
# Problem: cleanup deletes too much (wrong scoped_cleanup setting)
# Solution: verify scoped_cleanup is appropriate

@dataclass(frozen=True)
class MySchema(CartographyNodeSchema):
    # tenant-scoped resources — default, do not specify
    # scoped_cleanup: bool = True

    # global resources only — rare
    scoped_cleanup: bool = False  # vuln data, threat intel, etc.
```

For details on when to override `scoped_cleanup`, see the `add-node-type` skill.

### Data transform issues

```python
# Problem: KeyError during transform
# Solution: handle required vs optional fields correctly
{
    "id": data["id"],              # required — let it fail
    "name": data.get("name"),      # optional
    # avoid empty-string defaults — they hide missing data
    # "email": data.get("email", ""),
    "email": data.get("email"),    # use None default
}
```

### Schema definition issues

```python
# Problem: adding custom fields to schema classes
# Solution: remove them — only standard fields are recognised

@dataclass(frozen=True)
class MyRel(CartographyRelSchema):
    # Remove custom fields — they are silently ignored:
    # conditional_match_property: str = "some_field"
    # custom_flag: bool = True
    # extra_config: dict = {}

    # Keep only the standard relationship fields
    target_node_label: str = "TargetNode"
    target_node_matcher: TargetNodeMatcher = make_target_node_matcher(...)
    direction: LinkDirection = LinkDirection.OUTWARD
    rel_label: str = "CONNECTS_TO"
    properties: MyRelProperties = MyRelProperties()
```

For the standard schema fields, see the `add-node-type` skill.

### Performance issues

```python
# Problem: slow queries
# Solution: index frequently queried fields
email: PropertyRef = PropertyRef("email", extra_index=True)

# Query on indexed fields when possible
MATCH (u:User {id: $user_id})  # good — id is always indexed
MATCH (u:User {name: $name})   # bad — name might not be indexed
```

Fields used inside a `target_node_matcher` are indexed automatically.

### MatchLink issues

```python
# Problem: MatchLinks not creating relationships
# Solution: both source and target nodes must exist first

load(neo4j_session, SourceNodeSchema(), source_data, ...)   # 1. source nodes
load(neo4j_session, TargetNodeSchema(), target_data, ...)   # 2. target nodes

load_matchlinks(                                            # 3. then MatchLinks
    neo4j_session,
    YourMatchLinkSchema(),
    mapping_data,
    lastupdated=update_tag,
    _sub_resource_label="AWSAccount",
    _sub_resource_id=account_id,
)
```

```python
# Problem: MatchLink cleanup not working
# Solution: use GraphJob.from_matchlink with the right args
GraphJob.from_matchlink(
    YourMatchLinkSchema(),
    "AWSAccount",                          # _sub_resource_label
    common_job_parameters["AWS_ID"],       # _sub_resource_id
    common_job_parameters["UPDATE_TAG"],   # update_tag
).run(neo4j_session)
```

For full MatchLink details, see the `add-relationship` skill.

## Debugging tips

1. **Check existing patterns first.** Look at similar modules in `cartography/intel/` before inventing new ones.
2. **Verify imports.** All `CartographyNodeSchema` / `CartographyRelSchema` imports must point to `cartography.models.core.*`.
3. **Test transform functions** with real API responses.
4. **Validate Cypher in Neo4j Browser** when relationships are not appearing.
5. **Check file naming.** Module files should match the service name (`cartography/intel/lastpass/users.py`).
6. **Run tests incrementally.** After each change, run the integration test.
7. **Test through `sync()`**, not isolated `load()` calls.

## Key files

| File                                          | Purpose                                                                       |
| --------------------------------------------- | ----------------------------------------------------------------------------- |
| `cartography/client/core/tx.py`               | Core `load()` and `load_matchlinks()` — query generation lives here           |
| `cartography/graph/job.py`                    | `GraphJob` cleanup operations                                                 |
| `cartography/models/core/common.py`           | `PropertyRef` definition                                                      |
| `cartography/models/core/nodes.py`            | `CartographyNodeSchema`, `CartographyNodeProperties`, `ExtraNodeLabels`, etc. |
| `cartography/models/core/relationships.py`    | `CartographyRelSchema`, `LinkDirection`, matchers, MatchLinks                 |
| `cartography/config.py`                       | `Config` object — check missing fields here                                   |
| `cartography/cli.py`                          | Typer CLI with help panels                                                    |
| `cartography/data/indexes.cypher`             | Manual index definitions (legacy)                                             |
| `cartography/data/jobs/cleanup/`              | Legacy cleanup JSON files                                                     |
| `cartography/analysis/*/analysis.py`          | Typed analysis jobs (see `analysis-jobs` skill)                                |
| `cartography/data/jobs/analysis/`             | Legacy migration/cleanup JSON jobs                                             |
| `cartography/data/jobs/scoped_analysis/`      | Legacy scoped migration/cleanup JSON jobs                                      |

## Test utilities

```python
from tests.integration.util import check_nodes, check_rels


# Nodes
expected_nodes = {
    ("user-123", "alice@example.com"),
    ("user-456", "bob@example.com"),
}
assert check_nodes(neo4j_session, "YourServiceUser", ["id", "email"]) == expected_nodes


# Relationships
expected_rels = {
    ("user-123", "tenant-123"),
    ("user-456", "tenant-123"),
}
assert check_rels(
    neo4j_session,
    "YourServiceUser", "id",
    "YourServiceTenant", "id",
    "RESOURCE",
    rel_direction_right=True,
) == expected_rels
```

## Error message reference

| Error message                       | Likely cause                                | Solution                                       |
| ----------------------------------- | ------------------------------------------- | ---------------------------------------------- |
| `PropertyRef validation failed`     | Missing type annotation or `frozen=True`    | Check dataclass definition                     |
| `Node not found for relationship`   | Target node does not exist                  | Load parent nodes first                        |
| `GraphJob failed`                   | Wrong `common_job_parameters`               | Check `UPDATE_TAG` and tenant ID               |
| `KeyError: 'field_name'`            | Required field missing in API response      | Use `.get()` for optional fields               |
| `ModuleNotFoundError`               | Missing `__init__.py`                       | Add `__init__.py` to all directories           |
| `Relationship not created`          | Matcher property mismatch                   | Verify property names match exactly            |

## When to ask for help

Stop and ask the user when:

- Legacy Cypher queries contain unclear business logic.
- Complex relationships do not map clearly to the data model.
- Tests keep failing after multiple attempts.
- Multiple modules look interdependent.
- Performance issues persist after adding indexes.
- The graph contains unexpected data after sync.

