{"record":{"id":"efdc744900536ee6","repo":"alibaba/open-code-review","slug":"s-failed-w-efdc74","errorCode":null,"errorMessage":"%s failed: %w","messagePattern":"(.+?) failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/llm/keycmd.go","lineNumber":101,"sourceCode":"\terr := c.Run()\n\t// Checked first so a timeout reports as such instead of as the SIGKILL exit\n\t// status it produces. (Run has already joined every stdout copier, so the\n\t// buffer below is safe to read on all paths.)\n\tif ctx.Err() == context.DeadlineExceeded {\n\t\t// Wrap ctx.Err() so callers can errors.Is(err, context.DeadlineExceeded).\n\t\treturn \"\", fmt.Errorf(\"%s timed out after %s: %w\", label, keyCmdTimeout, ctx.Err())\n\t}\n\tif out.overflow {\n\t\treturn \"\", fmt.Errorf(\"%s produced more than 64KiB of output\", label)\n\t}\n\t// ErrWaitDelay only means an orphaned grandchild still holds the pipe; the\n\t// command itself exited fine and its output is already buffered, so use it\n\t// rather than surfacing an exec-internal error.\n\tif err != nil && !errors.Is(err, exec.ErrWaitDelay) {\n\t\t// Covers non-zero exit and command-not-found (the shell exits non-zero\n\t\t// and prints its not-found message on the child's stderr). ExitError.Stderr\n\t\t// stays nil because we assigned c.Stderr, so no output can leak here.\n\t\treturn \"\", fmt.Errorf(\"%s failed: %w\", label, err)\n\t}\n\n\t// Trim a trailing line break; multi-line output past that is ambiguous and refused.\n\t// ContainsAny (not Contains \"\\n\") so a lone interior CR is caught too: TrimRight\n\t// leaves it, TrimSpace below only strips the edges, and a CR inside a credential\n\t// makes net/http reject the Authorization header with an opaque error.\n\ttrimmed := strings.TrimRight(out.buf.String(), \"\\r\\n\")\n\tif strings.ContainsAny(trimmed, \"\\n\\r\") {\n\t\treturn \"\", fmt.Errorf(\"%s produced multi-line output; expected a single credential (pipe through 'head -n1' if your command prints more)\", label)\n\t}\n\t// Same reason as the line-break check, wider net: httpguts.ValidHeaderFieldValue\n\t// (what net/http enforces) rejects every byte below 0x20 except SP and TAB, plus\n\t// DEL. A NUL or VT smuggled in by e.g. `printf 'sk-a\\0b'` would otherwise reach\n\t// net/http as the opaque `invalid header field value for \"Authorization\"`.\n\t//\n\t// Deliberately before the TrimSpace below, so a trailing control byte is an\n\t// error naming its offset rather than silently stripped: only TAB, SP and the\n\t// line breaks already handled above are things a credential command can","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/llm/keycmd.go#L83-L119","documentation":"If the key command exits non-zero or cannot be executed, the failure is reported as `<label> failed: %w` wrapping the exec error. This covers non-zero exit codes and command-not-found (the shell exits non-zero and prints its message on the child's stderr). exec.ErrWaitDelay is deliberately excluded, since it only means an orphaned grandchild holds the pipe while the output is already valid.","triggerScenarios":"The configured credential command exits non-zero — wrong password, missing binary in PATH, denied permissions, or the command name does not exist.","commonSituations":"Typo in the command path; helper not installed in the environment the tool runs in (cron/CI PATH differs); secrets CLI failing auth; script erroring on a missing config file.","solutions":["Run the command manually with the same user/environment and check its exit code and stderr","Fix the underlying helper failure (credentials, config, permissions)","Correct the command name/path — ensure the binary is in PATH or use an absolute path","Inspect the wrapped exec.ExitError for the exit code; check the shell's stderr"],"exampleFix":"// before\nkeyCmd: \"op read op://vault/item/cred\" // op not installed on CI\n// after\nkeyCmd: \"/usr/local/bin/op read op://vault/item/cred\" // installed, absolute path","handlingStrategy":"try-catch","validationCode":"if _, err := exec.LookPath(\"<your-key-cmd-binary>\"); err != nil { /* not in PATH; install or use an absolute path */ }","typeGuard":null,"tryCatchPattern":"key, err := resolveKeyCmd(ctx, cfg)\nif err != nil {\n\tvar exitErr *exec.ExitError\n\tif errors.As(err, &exitErr) {\n\t\tlog.Printf(\"helper exited %d; check its auth/config\", exitErr.ExitCode())\n\t}\n\treturn err\n}","preventionTips":["Use absolute paths for credential binaries","Verify PATH in cron/CI environments matches your shell","Run the helper manually before wiring it into configuration"],"tags":["exec","credentials","exit-code"],"backgroundTag":"command-execution-failed","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}