{"record":{"id":"71afc60d0e22cf76","repo":"larksuite/cli","slug":"content-safety-panic-v","errorCode":null,"errorMessage":"content safety panic: %v","messagePattern":"content safety panic: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/output/emit_core.go","lineNumber":103,"sourceCode":"\t\treturn nil, nil\n\t}\n\n\ttype result struct {\n\t\talert *extcs.Alert\n\t\terr   error\n\t}\n\tch := make(chan result, 1)\n\tctx, cancel := context.WithTimeout(context.Background(), scanTimeout)\n\tdefer cancel()\n\n\t// Give the goroutine its own writer so it cannot race on errOut after timeout.\n\t// On success, we copy any provider notices to the real errOut.\n\t// On timeout, the buffer is owned by the goroutine until it finishes; no shared access.\n\tscanErrBuf := &bytes.Buffer{}\n\tgo func() {\n\t\tdefer func() {\n\t\t\tif r := recover(); r != nil {\n\t\t\t\tch <- result{nil, fmt.Errorf(\"content safety panic: %v\", r)}\n\t\t\t}\n\t\t}()\n\t\ta, e := p.Scan(ctx, extcs.ScanRequest{Path: cmdPath, Data: data, ErrOut: scanErrBuf})\n\t\tch <- result{a, e}\n\t}()\n\n\tvar res result\n\tselect {\n\tcase res = <-ch:\n\t\tif scanErrBuf.Len() > 0 {\n\t\t\t_, _ = io.Copy(errOut, scanErrBuf)\n\t\t}\n\tcase <-ctx.Done():\n\t\treturn nil, nil // timeout, fail-open; scanErrBuf stays with the goroutine\n\t}\n\n\tif res.err != nil {\n\t\tfmt.Fprintf(errOut, \"warning: content safety scan error: %v\\n\", res.err)","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/output/emit_core.go#L85-L121","documentation":"The output emit pipeline runs the content-safety provider Scan inside a goroutine whose deferred recover converts a panic into an error \"content safety panic: %v\" delivered over the result channel. It exists so a crashing safety scanner never takes down the CLI; the panic text is preserved for diagnosis.","triggerScenarios":"p.Scan panics during content-safety scanning of command output — e.g. a nil dereference or index panic inside the provider implementation on some input, or misuse of ScanRequest fields.","commonSituations":"Unusual command output (binary, huge payloads, odd encodings) triggering an edge-case bug in the scanner; a custom/patched safety provider with a bug; concurrent misuse of shared provider state.","solutions":["Read the %v panic value and stack context to find the panicking provider code.","Reproduce with the same command output to identify the triggering input.","Update/fix the safety provider implementation (the panic is the real bug; this envelope is just the safety net).","As an operator workaround, disable/replace the content-safety provider if your distribution allows it."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := emit(...); err != nil {\n    if strings.HasPrefix(err.Error(), \"content safety panic:\") {\n        log.Printf(\"safety scanner crashed, output suppressed: %v\", err)\n        // report bug upstream / fall back to raw output if policy allows\n    }\n}","preventionTips":["Keep the content-safety provider updated","Avoid piping pathological output (huge/binary) through scanners when possible","Report panic values from this envelope as provider bugs — the recover is a safety net"],"tags":["panic","recovery","content-safety","go"],"backgroundTag":"panic-in-provider","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}