CodeGraph records each VBA procedure's error policy in the procedure node's
metadata.errorPolicy object. Run the four queries below against the generated
.codegraph/codegraph.db SQLite database to find risky unprotected code,
open suppression scopes, user-facing error displays, and missing handlers.
If
CODEGRAPH_DIRis set, use that directory instead of.codegraph. Build or refresh the index before querying so these fields reflect the current source. SQLite's JSON functions (json_extract) are required.
This query narrows protection = 'none' to procedures with more than five
executable statements and an outgoing SQL-table, DoCmd, or filesystem-call
relationship. The exact statement count excludes blank/comment-only lines,
declarations, labels, and procedure boundary markers. Some SQL and DoCmd
references are initially owned by the module node, so the line-range join is
essential. Filesystem function calls are included by exact intrinsic name, and
reserved Kill, Open ... For ... As ..., and Close statement forms are
included only with their exact extractor provenance. This works both before and
after resolution because runtime references persist as declined-runtime rows;
unrelated, malformed, qualified, and user-procedure calls are not treated as risk.
WITH risky_relationships AS (
SELECT
e.source AS source_id,
e.line,
target.name AS risk_target,
target.kind AS risk_target_kind,
json_extract(e.metadata, '$.synthesizedBy') AS detected_by
FROM edges AS e
JOIN nodes AS target ON target.id = e.target
WHERE json_extract(e.metadata, '$.synthesizedBy') = 'vba-sql-table'
OR json_extract(e.metadata, '$.docmdVerb') IS NOT NULL
OR json_extract(e.metadata, '$.synthesizedBy') IN (
'vba-opens-form',
'vba-opens-report',
'vba-opens-query',
'vba-closes-form',
'vba-runs-macro',
'vba-opens-table',
'vba-applies-filter',
'vba-copies-object',
'vba-deletes-object',
'vba-renames-object',
'vba-selects-object',
'vba-browses-to',
'vba-outputs-to',
'vba-sends-object',
'vba-transfers-spreadsheet',
'vba-transfers-text',
'vba-transfers-database'
)
UNION ALL
SELECT
r.from_node_id AS source_id,
r.line,
r.reference_name AS risk_target,
'runtime-call' AS risk_target_kind,
json_extract(r.metadata, '$.synthesizedBy') AS detected_by
FROM unresolved_refs AS r
WHERE r.language = 'vba'
AND (
(
r.reference_kind IN ('calls', 'unqualified-ident')
AND json_extract(r.metadata, '$.synthesizedBy') IN (
'vba-paren-call-unresolved',
'vba-statement-call-unresolved'
)
AND lower(r.reference_name) IN (
'chdir', 'chdrive', 'dir', 'filecopy', 'filelen',
'getattr', 'mkdir', 'rmdir', 'setattr'
)
)
OR
(
r.reference_kind = 'calls'
AND json_extract(r.metadata, '$.synthesizedBy') =
'vba-filesystem-statement'
AND json_extract(r.metadata, '$.runtimeFamily') = 'filesystem'
AND lower(r.reference_name) IN ('kill', 'open', 'close')
AND json_extract(r.metadata, '$.operation') = lower(r.reference_name)
)
)
)
SELECT
p.name AS procedure,
p.qualified_name,
p.file_path,
p.start_line,
p.end_line,
json_extract(
p.metadata,
'$.errorPolicy.executableStatementCount'
) AS executable_statement_count,
risk.risk_target,
risk.risk_target_kind,
risk.detected_by
FROM nodes AS p
JOIN risky_relationships AS risk
ON risk.source_id = p.id
OR (
risk.line BETWEEN p.start_line AND p.end_line
AND EXISTS (
SELECT 1
FROM nodes AS relationship_owner
WHERE relationship_owner.id = risk.source_id
AND relationship_owner.file_path = p.file_path
)
)
WHERE p.kind = 'function'
AND p.language = 'vba'
AND json_extract(p.metadata, '$.errorPolicy.protection') = 'none'
AND json_extract(
p.metadata,
'$.errorPolicy.executableStatementCount'
) > 5
ORDER BY executable_statement_count DESC, p.file_path, p.start_line, risk_target;A row is a review candidate, not proof of a defect. Exactly six executable
statements meet the threshold; blank and comment-only padding does not. An
unresolved VBA table or Access-object reference can retain the synthetic class
placeholder kind; detected_by, rather than risk_target_kind, is the reliable
reason it appears here. Filesystem statement rows deliberately report
risk_target_kind = 'runtime-call'; their exact vba-filesystem-statement
provenance is the precision gate.
Snapshot validation. The current reproducible corpus identifies 27 distinct
procedures: 21 in 00_EXPEDIENTES, 0 in 00_GESTION_RIESGOS, and 6 in
HPS_SOLICITUDES. This intentionally narrower result requires a concrete SQL-table,
DoCmd, or precision-gated filesystem relationship; unlike the historical broad
185-procedure source-body census and later 103-procedure marker probe, it is snapshot
evidence rather than a stable cardinality assertion. Rows may repeat a procedure for
multiple risk targets, so compare corpora by distinct procedure identity.
resumeNextOpen is true when the last suppression event in a procedure opens a
scope and no later On Error GoTo 0 or On Error GoTo -1 closes it.
SELECT
p.name AS procedure,
p.qualified_name,
p.file_path,
p.start_line,
p.end_line,
json_extract(p.metadata, '$.errorPolicy.resumeNextOpen') AS resume_next_open
FROM nodes AS p
WHERE p.kind = 'function'
AND p.language = 'vba'
AND json_extract(p.metadata, '$.errorPolicy.resumeNextOpen') = 1
ORDER BY p.file_path, p.start_line;display means the handler displays or prints the error. mixed is included
because that handler displays the error and also records or re-raises it. The
left join keeps display procedures that have no resolved caller; when a caller
is known, reaches_display names it.
SELECT
display.name AS display_procedure,
display.qualified_name AS display_qualified_name,
display.file_path,
display.start_line,
json_extract(display.metadata, '$.errorPolicy.behavior') AS behavior,
caller.name AS reaches_display,
caller.qualified_name AS caller_qualified_name
FROM nodes AS display
LEFT JOIN edges AS incoming
ON incoming.target = display.id
AND incoming.kind = 'calls'
LEFT JOIN nodes AS caller ON caller.id = incoming.source
WHERE display.kind = 'function'
AND display.language = 'vba'
AND json_extract(display.metadata, '$.errorPolicy.behavior') IN ('display', 'mixed')
ORDER BY display.file_path, display.start_line, caller.qualified_name;This is one call hop, not a whole-program error-propagation claim. Repeat the incoming-call traversal, or use a recursive CTE, when you need every transitive caller that can reach a display point.
A non-null danglingTarget means the procedure contains On Error GoTo <label>
but does not define that label inside the same procedure.
SELECT
p.name AS procedure,
p.qualified_name,
p.file_path,
p.start_line,
json_extract(p.metadata, '$.errorPolicy.danglingTarget') AS dangling_target
FROM nodes AS p
WHERE p.kind = 'function'
AND p.language = 'vba'
AND json_extract(p.metadata, '$.errorPolicy.danglingTarget') IS NOT NULL
ORDER BY p.file_path, p.start_line;Fix or inspect these first: VBA cannot route the error to a label that is absent from that procedure, even if another procedure defines a label with the same name.