{"record":{"id":"f241259537f439d0","repo":"garrytan/gstack","slug":"save-failed-empty-body-cause-no-content-provide","errorCode":null,"errorMessage":"Save failed: empty body.\nCause: no content provided via --from-file or stdin.\nAction: pipe markdown into $B domain-skill save, or pass --from-file <path>.","messagePattern":"Save failed: empty body\\.\nCause: no content provided via --from-file or stdin\\.\nAction: pipe markdown into \\$B domain-skill save, or pass --from-file <path>\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"browse/src/domain-skill-commands.ts","lineNumber":113,"sourceCode":"  }\n  if (list.global.length > 0) {\n    if (lines.length > 0) lines.push('');\n    lines.push('Global (cross-project):');\n    for (const r of list.global) {\n      lines.push(`  ${r.host} — v${r.version}, ${r.body.length} bytes`);\n    }\n  }\n  return lines.join('\\n');\n}\n\n// ─── Subcommand handlers ────────────────────────────────────────\n\nasync function handleSave(args: string[], bm: BrowserManager): Promise<string> {\n  const page = bm.getPage();\n  const host = await deriveHostFromActiveTab(page);\n  const body = await readBodyFromArgs(args);\n  if (!body || !body.trim()) {\n    throw new Error(\n      'Save failed: empty body.\\n' +\n        'Cause: no content provided via --from-file or stdin.\\n' +\n        'Action: pipe markdown into $B domain-skill save, or pass --from-file <path>.'\n    );\n  }\n  // L1-L3 content filters (datamarking, hidden-element strip, ARIA regex,\n  // URL blocklist). The full L4 ML classifier runs at sidebar-agent prompt\n  // injection time, not here (CLAUDE.md: classifier can't import in compiled binary).\n  const filterResult = runContentFilters(body, page.url(), 'domain-skill-save');\n  if (filterResult.blocked) {\n    logTelemetry({ event: 'domain_skill_save_blocked', host, reason: filterResult.message });\n    throw new Error(\n      `Save blocked: ${filterResult.message}\\n` +\n        'Cause: skill body trips L1-L3 content filters (likely contains URL blocklist match or ARIA injection patterns).\\n' +\n        'Action: review the body for suspicious instruction-like content; rewrite and retry.'\n    );\n  }\n  // L1-L3 score is binary (passed or not). For the L4 score field we leave 0","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/domain-skill-commands.ts#L95-L131","documentation":"Error \"Save failed: empty body.\nCause: no content provided via --from-file or stdin.\nAction: pipe markdown into $B domain-skill save, or pass --from-file <path>.\" thrown in garrytan/gstack.","triggerScenarios":"Thrown at browse/src/domain-skill-commands.ts:113 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":[],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}