The config that lied at the boundary
Scenario
A crawler loads its settings from a JSON file: a maximum crawl depth and a per-page-type score weight table. The loader compiles clean under strict: true and every type reads correctly in the IDE. In production the crawler dies two ways: scorePage throws TypeError: Cannot read properties of undefined (reading 'article') deep in the scoring pass, and on another config file the crawl recurses until RangeError: Maximum call stack size exceeded. Neither stack trace mentions the config loader. Find the real bug and say why both crashes surface so far from it.
1interface CrawlConfig {2 maxDepth: number;3 weights: Record<string, number>; // score per page type4}5 6function loadConfig(text: string): CrawlConfig {7 return JSON.parse(text) as CrawlConfig; // "as" — trust me, compiler8}9 10interface Page { type: string; links: Page[] }11 12function scorePage(page: Page, config: CrawlConfig): number {13 return config.weights[page.type] ?? 0; // throws when weights is undefined14}15 16function crawl(page: Page, depth: number, config: CrawlConfig, out: string[]): void {17 if (depth === config.maxDepth) return; // never true when maxDepth is "3"18 out.push(page.type);19 for (const child of page.links) crawl(child, depth + 1, config, out);20}21 22// The file was hand-edited: maxDepth quoted, weights misspelled.23const config = loadConfig('{"maxDepth": "3", "weigths": {"article": 5, "index": 1}}');24 25const home: Page = { type: 'index', links: [] };26const article: Page = { type: 'article', links: [home] };27home.links.push(article); // real sites have cycles28 29console.log(scorePage(article, config)); // TypeError: reading 'article' of undefined30const visited: string[] = [];31crawl(home, 0, config, visited); // RangeError: Maximum call stack size exceededYour task
- What is the return type of
JSON.parse, and what doesas CrawlConfigcheck at compile time and do at runtime? - Explain the
TypeErrorinscorePage: the code even has?? 0— why does the guard not help? - Explain the
RangeError:depth === config.maxDepthwithmaxDepthholding the string"3". Woulddepth >= config.maxDepthhave "worked", and why is that worse? - Rewrite the loader so a bad file fails *at the boundary* with a message naming the problem: parse into
unknownand narrow with a type guard. - Where else does this pattern appear besides
JSON.parse? Name two more trust boundaries and the general rule. - State the cost of validation relative to the crawl itself.
Work it out
Write your analysis before revealing anything. The self-check below compares it against what a strong answer contains.
Reveal
Progressive — each section builds on the previous one.
Self-check
Tick what your analysis covered. Be honest — this feeds your readiness profile.