{"record":{"id":"0045097ade6d8beb","repo":"affaan-m/ECC","slug":"invalid-issuenumber-expected-positive-integer-go","errorCode":null,"errorMessage":"invalid issueNumber: expected positive integer, got ${JSON.stringify(issueNumber)}","messagePattern":"invalid issueNumber: expected positive integer, got (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/github-coordination/actions.js","lineNumber":27,"sourceCode":"  buildIssueStateFromAction,\n  desiredLabelsForState,\n  getCoordinationState,\n  summarizeStateForOutput,\n  syncIssueLabels,\n  verifyDependenciesClosed,\n} = require('./state');\nconst { upsertCoordinationWorkItem } = require('./store');\nconst { extractIssueReferences, extractTasks } = require('./parsing');\n\nfunction assertValidRepo(repo) {\n  if (typeof repo !== 'string' || !repo.trim()) {\n    throw new Error(`invalid repo: expected non-empty string, got ${JSON.stringify(repo)}`);\n  }\n}\n\nfunction assertValidIssueNumber(issueNumber) {\n  if (!Number.isFinite(issueNumber) || issueNumber <= 0 || !Number.isInteger(issueNumber)) {\n    throw new Error(`invalid issueNumber: expected positive integer, got ${JSON.stringify(issueNumber)}`);\n  }\n}\n\nfunction staleCoordinationLabels(issue, nextLabels, policy) {\n  const epicLabel = policy.labels && policy.labels.epic;\n  return normalizeLabels(issue.labels).filter(l =>\n    (l.startsWith('coordination:') || l === epicLabel) && !nextLabels.includes(l)\n  );\n}\n\n// applyClaim performs a read (getIssue) → check (assertIssueClaimable) → write\n// (editIssue) sequence that is NOT atomic. Two concurrent callers can both read\n// an unclaimed issue, pass the check, and both succeed — resulting in a\n// double-claim. A code-review finding suggested fixing this via\n// context.store.acquireLock(repo, issueNumber), but that API does not exist in\n// store.js; adding a call to it would throw at runtime. Left as-is until a\n// locking primitive is available — callers should prevent races via external\n// serialization (e.g. a serialized job queue or GitHub branch-protection rule).","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/github-coordination/actions.js#L9-L45","documentation":"Thrown by assertValidIssueNumber when issueNumber is not a finite positive integer. GitHub issue numbers are positive integers; negatives, zero, fractions, NaN, or non-numeric strings all make gh issue view fail or target the wrong issue. The guard uses Number.isFinite + > 0 + Number.isInteger to reject all malformed inputs before any gh call.","triggerScenarios":"Passing issueNumber: 0, -5, 3.5, NaN, 'abc', or undefined; reading the number from a string ('#42') without stripping the '#'; parseInt on an empty string yielding NaN.","commonSituations":"CLI arg parsed as string not converted to number; issue ref like '#42' passed raw; URL param not validated; off-by-one or default 0 sentinel leaked into the call.","solutions":["Pass a positive integer (e.g. 42) — convert and validate before calling.","Strip leading '#' and parse: const n = Number.parseInt(String(raw).replace(/^#/, ''), 10); assert Number.isInteger(n) && n > 0.","Validate at the CLI/config boundary so the coordination functions receive clean numbers.","Add a unit test with 0, -1, 3.5, NaN, 'abc' to confirm the guard."],"exampleFix":"// before\napplyPublish(repo, rawIssue);\n\n// after — coerce and validate\nconst issueNumber = Number.parseInt(String(rawIssue).replace(/^#/, ''), 10);\nif (!Number.isInteger(issueNumber) || issueNumber <= 0) {\n  throw new Error(`issue number must be a positive integer, got ${rawIssue}`);\n}\napplyPublish(repo, issueNumber);","handlingStrategy":"validation","validationCode":"if (!Number.isInteger(issueNumber) || issueNumber <= 0) {\n  throw new Error(`issueNumber must be a positive integer, got ${JSON.stringify(issueNumber)}`);\n}","typeGuard":"function isPositiveInt(n) {\n  return Number.isInteger(n) && n > 0;\n}","tryCatchPattern":"try {\n  applyPublish(repo, issueNumber);\n} catch (e) {\n  if (/invalid issueNumber/.test(e.message)) { console.error('Pass a positive integer issue number'); process.exit(2); }\n  throw e;\n}","preventionTips":["Strip '#' and parse issue refs to integers at the input boundary.","Never pass 0, -1, NaN, or strings into coordination functions.","Validate numeric CLI args before calling the API."],"tags":["github-coordination","validation","precondition","numeric"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}