Skip to content

False Positive "missing-attribute" on Union Types #549

Open
@kimasplund

Description

@kimasplund

Describe the Bug

Pyrefly Bug Report: False Positive "missing-attribute" on Union Types

Summary

Pyrefly 0.20.2 incorrectly reports "missing-attribute" errors when accessing methods on dictionary values within union types, even when proper type narrowing or initialization guarantees the correct type.

Environment

  • Pyrefly version: 0.20.2
  • Python version: 3.12
  • OS: Linux

Minimal Reproducible Example

from typing import Dict, Any, List, Union

def process_sla_result() -> Dict[str, Any]:
    # Initialize with explicit structure
    sla_result = {
        "sla_id": "sla-001",
        "sla_name": "Response Time SLA",
        "compliant": True,
        "violations": [],  # Clearly a list
        "metrics_checked": {}
    }
    
    # Pyrefly reports these as errors:
    # ERROR Object of class `bool` has no attribute `append` [missing-attribute]
    # ERROR Object of class `dict` has no attribute `append` [missing-attribute]
    sla_result["violations"].append({
        "type": "response_time",
        "severity": "high"
    })
    
    return sla_result

# Another example with TypedDict
from typing import TypedDict, List

class SLAResult(TypedDict):
    violations: List[Dict[str, Any]]
    compliant: bool

def process_typed() -> SLAResult:
    result: SLAResult = {
        "violations": [],
        "compliant": True
    }
    
    # Still reports error even with TypedDict
    result["violations"].append({"error": "timeout"})
    
    return result

Expected Behavior

  • Pyrefly should recognize that sla_result["violations"] is initialized as a list
  • When using TypedDict, the type of violations is explicitly List[Dict[str, Any]]
  • No "missing-attribute" error should be reported for the append method

Actual Behavior

Pyrefly reports multiple errors:

ERROR Object of class `bool` has no attribute `append` [missing-attribute]
ERROR Object of class `dict` has no attribute `append` [missing-attribute]
ERROR Object of class `int` has no attribute `append` [missing-attribute]
ERROR Object of class `str` has no attribute `append` [missing-attribute]

Root Cause Analysis

  1. When accessing dict[key], pyrefly considers all possible types in the union Dict[str, Any]
  2. The Any type expands to a union including bool | dict | int | str | list | ...
  3. Pyrefly checks each type in the union and reports errors for types that don't have append
  4. It doesn't recognize that in this specific context, the value is guaranteed to be a list

Impact

  • 378+ false positive "missing-attribute" errors in our codebase
  • Makes pyrefly output noisy and less useful
  • Developers may miss real type errors among the false positives

Suggested Fix

  1. Improve flow-sensitive type analysis to track dictionary value types after initialization
  2. When a dictionary key is initialized with a specific type, narrow the type for that key
  3. Consider TypedDict annotations when analyzing dictionary access
  4. Reduce false positives by considering whether ANY type in the union has the attribute

Workarounds

  1. Use explicit type annotations:

    violations: List[Dict[str, Any]] = sla_result["violations"]
    violations.append({"error": "timeout"})
  2. Use isinstance checks:

    if isinstance(sla_result["violations"], list):
        sla_result["violations"].append({"error": "timeout"})
  3. Use TypedDict throughout:

    result: SLAResult = {"violations": [], "compliant": True}
    violations = result["violations"]  # Type is known
    violations.append({"error": "timeout"})

Additional Context

This pattern is extremely common in Python code dealing with JSON-like data structures, configuration management, and API responses. The false positives significantly impact pyrefly's usability for real-world Python projects.

Sandbox Link

No response

(Only applicable for extension issues) IDE Information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    UserBugs reported by external users that should be prioritisedquestionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions