{"record":{"id":"47afe62982f52714","repo":"garrytan/gstack","slug":"save-blocked-filterresult-message-cause-skill","errorCode":null,"errorMessage":"Save blocked: ${filterResult.message}\nCause: skill body trips L1-L3 content filters (likely contains URL blocklist match or ARIA injection patterns).\nAction: review the body for suspicious instruction-like content; rewrite and retry.","messagePattern":"Save blocked: (.+?)\nCause: skill body trips L1-L3 content filters \\(likely contains URL blocklist match or ARIA injection patterns\\)\\.\nAction: review the body for suspicious instruction-like content; rewrite and retry\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"browse/src/domain-skill-commands.ts","lineNumber":125,"sourceCode":"\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\n  // (meaning \"not yet scanned by ML classifier\") — sidebar-agent fills this\n  // in on first prompt-injection load.\n  const slug = getCurrentProjectSlug();\n  const row = await writeSkill({\n    host,\n    body,\n    projectSlug: slug,\n    source: 'agent',\n    classifierScore: 0, // L4 deferred to load-time\n  });\n  logTelemetry({ event: 'domain_skill_saved', host, scope: row.scope, state: row.state, bytes: body.length });\n  return formatSavedOk(row, slug);","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/domain-skill-commands.ts#L107-L143","documentation":"Error \"Save blocked: ${filterResult.message}\nCause: skill body trips L1-L3 content filters (likely contains URL blocklist match or ARIA injection patterns).\nAction: review the body for suspicious instruction-like content; rewrite and retry.\" thrown in garrytan/gstack.","triggerScenarios":"Thrown at browse/src/domain-skill-commands.ts:125 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"}