{"record":{"id":"812104f72d011ba8","repo":"abhigyanpatwari/GitNexus","slug":"timeout","errorCode":"timeout","errorMessage":"Could not acquire the sync lock for group \"${path.basename(groupDir)}\" (${getGroupSyncLockDir(groupDir)}). ${err.message} Nothing was written and this group was not synced.","messagePattern":"Could not acquire the sync lock for group \"(.+?)\" \\((.+?)\\)\\. (.+?) Nothing was written and this group was not synced\\.","errorType":"exception","errorClass":"GroupSyncLockError","httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/group/group-lock.ts","lineNumber":154,"sourceCode":"      timeoutMs: GROUP_SYNC_LOCK_TIMEOUT_MS,\n      // `acquireIndexLock`'s own `log` texts name an \"analyze\" holder, which\n      // misattributes a group-sync wait — the same reason `withRegistryLock`\n      // supplies its own line instead of passing `log` through.\n      onWaitStart: () =>\n        logger.info(\n          { groupDir },\n          'Waiting for another GitNexus process to finish syncing this group…',\n        ),\n    });\n  } catch (err) {\n    // The inherited message names \"another gitnexus analyze\" as the holder —\n    // a cause this detection path cannot establish. Nothing but a group sync\n    // ever locks `<groupDir>/sync-lock` (see the module header), and on the\n    // socket backend the holder is not identifiable at all. Re-word it around\n    // what IS known: which group, which operation, and how long we waited.\n    if (err instanceof IndexLockTimeoutError) {\n      if (isIndexLockGuardTimeout(err)) {\n        throw new GroupSyncLockError(\n          'timeout',\n          groupDir,\n          `Could not acquire the sync lock for group \"${path.basename(groupDir)}\" ` +\n            `(${getGroupSyncLockDir(groupDir)}). ${err.message} ` +\n            `Nothing was written and this group was not synced.`,\n          err,\n        );\n      }\n      throw new GroupSyncLockError(\n        'timeout',\n        groupDir,\n        `Timed out after ${Date.now() - acquireStartedAt}ms waiting for the sync lock on ` +\n          `group \"${path.basename(groupDir)}\" (${getGroupSyncLockDir(groupDir)}). ` +\n          // `holderKnown` is false on the socket backend and on the file\n          // backend's malformed/vanished-lock timeouts, where `holder` is a\n          // placeholder (`pid -1`). Presenting that as a real owner would be the\n          // same unestablished claim in a new form.\n          (err.holderKnown","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/ac9a4e9abd8fd3058c070b72c23402a4f887929a/gitnexus/src/core/group/group-lock.ts#L136-L172","documentation":"withGroupSyncLock failed to acquire the per-group sync lock (`<groupDir>/sync-lock`) because the underlying index-lock wait timed out with a guard timeout (isIndexLockGuardTimeout). Only a group sync ever holds this lock, so the error is worded around what is known: which group, which lock path, and the underlying wait error. Nothing was written and the group was not synced.","triggerScenarios":"Calling a group sync API wrapped in withGroupSyncLock while another sync of the same group is in progress (or a stale lock from a crashed sync exists), and the IndexLockTimeoutError is classified as a guard timeout.","commonSituations":"Two concurrent `gitnexus` syncs targeting the same group (e.g. MCP server and CLI both syncing); a previous sync crashed leaving a lock file behind; slow disk making the guard wait exceed its budget.","solutions":["Wait for the other sync of this group to finish, then re-run the sync.","Check for stale locks in the group's sync-lock directory (getGroupSyncLockDir) and remove them only if no sync process is running.","Ensure only one GitNexus process (MCP server, serve, CLI) syncs the same group at a time."],"exampleFix":"// before: two concurrent syncs of the same group\nawait Promise.all([syncGroup(g), syncGroup(g)]);\n// after\nawait syncGroup(g); // serialize; or use a shared queue per groupDir","handlingStrategy":"retry","validationCode":"import fs from 'node:fs';\n// Check no sync lock exists before starting\nif (fs.existsSync(groupSyncLockPath)) {\n  console.warn('Another sync of this group may be running; wait before retrying.');\n}","typeGuard":"const isGroupSyncLockError = (e: unknown): e is GroupSyncLockError =>\n  e instanceof GroupSyncLockError && e.code === 'timeout';","tryCatchPattern":"try {\n  await withGroupSyncLock(groupDir, () => doSync());\n} catch (err) {\n  if (isGroupSyncLockError(err)) {\n    console.error(`Group ${err.groupDir} is being synced elsewhere; nothing was written.`);\n  } else throw err;\n}","preventionTips":["Serialize group syncs through a single process or job queue.","Add retry-with-backoff around syncs that may contend for the same group.","After crashes, verify no sync process is alive before manually removing sync-lock files."],"tags":["locking","concurrency","timeout","group-sync"],"backgroundTag":"lock-acquisition-timeout","analyzedSha":"ac9a4e9abd8fd3058c070b72c23402a4f887929a","analyzedAt":"2026-09-15T23:29:44.066Z","contentChangedAt":"2026-09-15T23:29:44.066Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}