PostHog / PostHog/posthog

A view can be suggested as the fix for an unresolved table inside its own body

Open
#99,993 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Python
Stars
39.9k
Forks
3.4k
Avg merge
6h 51m
Merged PRs (30d)
232

Description

Bug description

When a table name inside a view's body does not resolve, the "Did you mean …?" suggestion list
can include the view currently being resolved. Taking that suggestion makes the view select
from itself, which then fails as a cycle.

Mechanism

The table-suggestion candidate set is built in posthog/hogql/database/database.py, ending at
line 875:

return difflib.get_close_matches(name, sorted(candidates), n=limit, cutoff=0.7)

The candidates include every view name:

candidates.update(self._view_table_names)

There is already one self-exclusion, but it only drops a candidate equal to the queried name:

# Drop any candidate that matches the input — suggesting `persons` for `persons`
# is noise …
candidates = {c for c in candidates if c.casefold() != lowered}

The name being resolved is by definition not the enclosing view's name (otherwise it would have
resolved), so the enclosing view survives that filter and stays eligible as a near match.

Why the data to fix it already exists, but does not reach the suggestion site

Two resolvers track "am I inside a view" differently:

  • posthog/hogql/resolver.py:384self.current_view_depth: int = 0, a counter
  • products/data_modeling/backend/models/modeling.py:165self.resolving_views: set[str], a name set

A counter can say how deep the resolution is, but not which view it is inside, so the base
resolver cannot exclude it. The data-modeling resolver does know the name, but nothing in
modeling.py filters suggestions (no reference to suggest, cutoff, or get_close_matches),
so the name never reaches the candidate filter either.

Suggested direction

Carry the enclosing view name down to the suggestion site and exclude it, rather than adding a
second self-check at the call site. Lifting the name set into the base resolver would fix every
path at once.

If that lift happens, note that the discard-in-finally pattern in modeling.py:294 is not
safe once a view can be entered twice on different branches — it needs add-if-absent /
remove-what-I-added.

Notes

Traced in the code on master today. Not executed.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in posthog/hogql/database/database.py around line 875, then read the view-tracking logic in posthog/hogql/resolver.py:384 and products/data_modeling/backend/models/modeling.py:165 and :294. Trace how the enclosing view name could reach suggestion generation, and verify that suggestions for unresolved tables no longer include that view, including nested or repeated resolution paths.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.