{"record":{"id":"e19bb83f1514edc8","repo":"alibaba/open-code-review","slug":"ocr-llm-timeout-must-be-an-integer-seconds-w","errorCode":null,"errorMessage":"OCR_LLM_TIMEOUT must be an integer (seconds): %w","messagePattern":"OCR_LLM_TIMEOUT must be an integer \\(seconds\\): %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/llm/resolver.go","lineNumber":210,"sourceCode":"\t\t\t\tep.ExtraHeaders[key] = value\n\t\t\t}\n\t\t}\n\t}\n\treturn ep\n}\n\n// parseTimeoutEnv reads and validates the OCR_LLM_TIMEOUT environment variable.\n// Returns the parsed duration and true if set, or 0 and false if unset/empty.\n// Returns an error for invalid values (non-integer, negative, overflow) to give\n// the user clear feedback instead of silently falling back to the default.\nfunc parseTimeoutEnv() (time.Duration, bool, error) {\n\traw := strings.TrimSpace(os.Getenv(envOCRLLMTimeout))\n\tif raw == \"\" {\n\t\treturn 0, false, nil\n\t}\n\tsec, err := strconv.Atoi(raw)\n\tif err != nil {\n\t\treturn 0, false, fmt.Errorf(\"OCR_LLM_TIMEOUT must be an integer (seconds): %w\", err)\n\t}\n\td, err := validateTimeoutSec(sec)\n\tif err != nil {\n\t\treturn 0, false, fmt.Errorf(\"OCR_LLM_TIMEOUT: %w\", err)\n\t}\n\treturn d, true, nil\n}\n\n// validateTimeoutSec converts a config-file timeout (in seconds) to time.Duration.\n// Returns 0 for zero input (use default). Rejects negative values and overflow.\nfunc validateTimeoutSec(sec int) (time.Duration, error) {\n\tif sec == 0 {\n\t\treturn 0, nil\n\t}\n\tif sec < 0 {\n\t\treturn 0, fmt.Errorf(\"timeout_sec must be non-negative, got %d\", sec)\n\t}\n\t// Guard against overflow: time.Duration is int64 nanoseconds.","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/llm/resolver.go#L192-L228","documentation":"OCR_LLM_TIMEOUT is interpreted strictly as an integer number of seconds. parseTimeoutEnv uses strconv.Atoi on the trimmed value; anything non-numeric (\"30s\", \"2m\", \"\") beyond empty produces this wrapped error. Like other global overrides, it fails fast before credential prompts.","triggerScenarios":"Setting OCR_LLM_TIMEOUT to a duration-style string (\"30s\", \"1m30s\"), a float (\"2.5\"), or any non-integer while ResolveEndpointWithOptions runs parseEnvOverrides.","commonSituations":"Users copying Go duration syntax from other tools; assuming the variable accepts \"30s\" because many CLIs do; a locale or whitespace artifact is handled by TrimSpace, so the usual cause is a unit suffix.","solutions":["Set OCR_LLM_TIMEOUT to a plain integer of seconds, e.g. 120 instead of \"2m\"","Remove the unit suffix and any surrounding characters","Unset the variable to use the client default (5 minutes)"],"exampleFix":"// before\nexport OCR_LLM_TIMEOUT=\"90s\"\n// after\nexport OCR_LLM_TIMEOUT=90","handlingStrategy":"validation","validationCode":"raw := strings.TrimSpace(os.Getenv(\"OCR_LLM_TIMEOUT\"))\nif raw != \"\" {\n    if _, err := strconv.Atoi(raw); err != nil {\n        return fmt.Errorf(\"OCR_LLM_TIMEOUT must be plain seconds integer, got %q\", raw)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"OCR_LLM_TIMEOUT must be an integer\") {\n    return fmt.Errorf(\"export OCR_LLM_TIMEOUT=90 instead of %q\", os.Getenv(\"OCR_LLM_TIMEOUT\"))\n}","preventionTips":["Use bare integers (seconds), never \"30s\"/\"2m\" duration strings","Prefer OCR_LLM_TIMEOUT=0 or unset over unit-style values","Document the variable in team onboarding to prevent copy-paste of Go duration syntax"],"tags":["env-vars","parsing","timeout"],"backgroundTag":"invalid-env-var-format","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}