Skip to content

TypeError: 'NoneType' * 'float' in generate_forensic_report when betweenness_score is None (signal_processor.py:1686) #18

@Abramel

Description

@Abramel

Summary

galaxyscope crashes during forensic report generation on small / sparse Python repositories. The default-value pattern net.get("betweenness_score", 0.0) does not guard against the key being present but set to None, which the centrality producer can return.

Environment

  • gitgalaxy: v6.2.0 (from python -m gitgalaxy.galaxyscope --help)
  • Python: 3.14.2
  • OS: Windows 11
  • Install: cloned main at 1a326044c4c5a969de28a7fdf5df451bdd1d2afc, run via PYTHONPATH=. python -m gitgalaxy.galaxyscope

Reproduction

Reproduces consistently on at least two unrelated Python repos in the 16–60 file range:

python -m gitgalaxy.galaxyscope /path/to/small-python-repo

Logs show all earlier phases pass cleanly (guardrails, AppSec sensor, auditor, cartographer, synthesis), then:

[INFO] [GalaxyScope.processing] Synthesizing repository metrics across 26 artifacts (22 verified, 4 unparsable)...
[INFO] [GalaxyScope.processing] Synthesis Complete | Volatility Index: 0.00 | Darkness Ratio: 15.4%
[INFO] [GalaxyScope.processing] Generating forensic exposure rankings...
[CRITICAL] FATAL_SYSTEM_COLLAPSE: unsupported operand type(s) for *: 'NoneType' and 'float'
File "gitgalaxy/galaxyscope.py", line 633, in run_mission
    report = self.processor.generate_forensic_report(repository_graph)
File "gitgalaxy/physics/signal_processor.py", line 1686, in generate_forensic_report
    bottlenecks["contagious_mutation"].append({"path": p, "score": round(btw * flux_risk, 3), ...})
TypeError: unsupported operand type(s) for *: 'NoneType' and 'float'

--db-only does not bypass the failure (the report path runs unconditionally).

Likely cause

Lines 1678–1680:

btw   = net.get("betweenness_score",       0.0)
close = net.get("closeness_score",         0.0)
pr    = net.get("normalized_blast_radius", 0.0)

dict.get(key, default) only returns the default when the key is missing. If the key is present and the value is None (which the centrality stage appears to emit on graphs below some edge-density threshold), the variables are None, and the btw * flux_risk / close * err_risk / pr * doc_risk multiplications on lines 1686–1688 raise TypeError.

Suggested fix

btw   = net.get("betweenness_score")       or 0.0
close = net.get("closeness_score")         or 0.0
pr    = net.get("normalized_blast_radius") or 0.0

(or equivalent if ... is None guards). Lines 1687–1688 share the same vulnerability shape via close and pr; the or 0.0 form fixes all three at once.

Alternatively, fix it upstream so the centrality producer emits 0.0 instead of None for the empty-graph case.

Impact

Small/sparse Python repos — exactly the case where a quick galaxyscope pass would otherwise be a fast first read on a project — currently produce zero output (no JSON, no SQLite written; the failure happens before persistence).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions