mutated × unstructured — blows up live on input you didn't expect

Shape-Drift AttributeError

An attribute set on only some code paths, read on a path that assumes it always exists.

01the recipe

In the wild

example.py
# SMELL: an attribute added only on one path; another path assumes it exists.
# (improper-initialization x duck-typing-without-contracts)
class Job:
    def __init__(self): self.status = "new"

def run(job):
    if job.status == "retry":
        job.result = recompute()     # 'result' set ONLY on the retry path
    report(job.result)               # AttributeError when status != "retry"

# RIGHT: give the shape a contract; every field exists from construction.
class Job:
    def __init__(self):
        self.status = "new"
        self.result = None           # always present
Because result is added on only one branch, every other path reaches for an attribute that was never set. Duck typing hides it until the missing-attribute path runs on real data -- an AttributeError live, not in dev.
// observed
drift: AttributeError: 'Job' object has no attribute 'result'
right: field present from construction; absence handled as None
02weakness catalog

Mapped weaknesses (CWE)

On its own, this defect is catalogued by MITRE as one or more of these weaknesses. The exploitable vulnerability usually appears only when it chains or combines with another.