plandex-ai/plandex · error
invalid lock scope: %v
Error message
invalid lock scope: %v
What it means
After fetching existing locks, lockRepoDB evaluates acquisition per lock; the read/write logic only handles LockScopeRead and LockScopeWrite. If scope somehow holds any other value at this point (it should have been caught by earlier validation), the loop returns "invalid lock scope: %v", which propagates to lock acquisition retry logic.
Source
Thrown at app/server/db/locks.go:275
if scope == LockScopeRead {
// if we're trying to acquire a read lock, we can do so unless there's a conflicting lock
// a write lock always conflicts with a read lock (regardless of branch)
// a read lock conflicts if it's for a different branch (since it would need to checkout a different branch in the middle of an already-running read)
if lock.Scope == LockScopeWrite {
canAcquire = false
break
} else if lock.Scope == LockScopeRead {
if lockBranch != branch {
canAcquire = false
break
}
}
} else if scope == LockScopeWrite {
// if we're trying to acquire a write lock, we can only do so if there's no other lock (read or write)
canAcquire = false
break
} else {
err = fmt.Errorf("invalid lock scope: %v", scope)
return "", err
}
}
if !canAcquire {
if locksVerboseLogging {
log.Println("can't acquire lock.", "numRetry:", numRetry)
}
conflictErr := errors.New("lock conflict: cannot acquire read/write lock")
log.Printf("[Lock][%d] can't acquire lock, retrying: %v | reason: %s | now: %s | locks:\n%s\n", goroutineID, conflictErr, params.Reason, now, spew.Sdump(locks))
return retryWithExponentialBackoff(params.Ctx, conflictErr, numRetry, func(nextAttempt int) (string, error) {
return lockRepoDB(params, nextAttempt)
})
}
if locksVerboseLogging {
log.Println("can acquire lock - inserting new lock")View on GitHub (pinned to e2d772072e)
Solutions
- Always pass db.LockScopeRead or db.LockScopeWrite; never construct custom LockScope values.
- Call the exported lock API rather than lockRepoDB directly so upfront validation runs.
- Extend the acquisition branch if you genuinely added a new scope constant.
- Add a default case/test asserting LockScope only has the two valid values.
Example fix
// before
scope := db.LockScope(req.Scope) // arbitrary user string
// after
var scope db.LockScope
switch req.Scope {
case "read": scope = db.LockScopeRead
case "write": scope = db.LockScopeWrite
default: return fmt.Errorf("unsupported scope %q", req.Scope)
} Defensive patterns
Strategy: validation
Validate before calling
if params.Scope != db.LockScopeRead && params.Scope != db.LockScopeWrite {
return fmt.Errorf("scope must be LockScopeRead or LockScopeWrite")
} Type guard
func isKnownLockScope(s db.LockScope) bool {
return s == db.LockScopeRead || s == db.LockScopeWrite
} Try / catch
lockId, err := db.LockRepo(ctx, cancel, params)
if err != nil && strings.Contains(err.Error(), "invalid lock scope") {
return fmt.Errorf("programming error: scope %q is not supported", params.Scope) // do not retry
} Prevention
- Never invent new LockScope values; restrict the type to the two exported constants.
- Call the exported lock API so upfront scope validation runs before the acquisition loop.
- Add an exhaustive-switch test over LockScope to catch any newly added constant early.
When it happens
Trigger: A LockScope value that passes none of the read/write equality checks in the acquisition loop — practically a zero-value/empty scope or a constant mismatch introduced after the initial validation.
Common situations: Custom LockScope constants added by a fork without extending the acquisition branch; scope mutated between validation and the loop; a default-constructed LockRepoParams whose Scope validation was bypassed by calling lockRepoDB directly.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- orgId is required
- planId is required
- invalid lock scope: %s
- error prompting host: %v
- error prompting email: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/8118a332cf0c4fd9.
Report an issue: GitHub.