{"record":{"id":"c7e3be456e6878a4","repo":"affaan-m/ECC","slug":"claim-transaction-failed-no-permission-granted","errorCode":null,"errorMessage":"claim transaction failed; no permission granted","messagePattern":"claim transaction failed; no permission granted","errorType":"exception","errorClass":"ClaimError","httpStatus":null,"severity":"error","filePath":"skills/operator-approval-loop/references/approval_claims.py","lineNumber":47,"sourceCode":"\n@contextmanager\ndef _transaction(db, now):\n    # Never return permission whose commit belongs to an outer caller transaction.\n    if db.in_transaction:\n        raise ClaimError('a top-level committed transaction is required')\n    if type(now) is not int or now < 0:\n        raise ClaimError('now must be a nonnegative integer')\n    if any(db.execute(f'PRAGMA {name}').fetchone()[0] != 1\n           for name in ('foreign_keys', 'recursive_triggers')):\n        raise ClaimError('required SQLite guards are disabled')\n    try:\n        db.execute('BEGIN IMMEDIATE')\n        yield\n        db.commit()\n    except BaseException as error:\n        db.rollback()\n        if isinstance(error, sqlite3.Error):\n            raise ClaimError('claim transaction failed; no permission granted') from error\n        raise\n\n\ndef _snapshot(db, obligation_id, decision_id):\n    row = db.execute('''SELECT * FROM approval_bound_drafts\n        WHERE obligation_id=? AND decision_id=?''', (obligation_id, decision_id)).fetchone()\n    if row is None:\n        raise ClaimError('a current bound approved draft is required')\n    try:\n        digest = hashlib.sha256(row['draft_text'].encode('utf-8')).hexdigest()\n    except (AttributeError, UnicodeError) as error:\n        raise ClaimError('approved text must be valid UTF-8 text') from error\n    stored_digest = row['draft_sha256']\n    if (not isinstance(stored_digest, str) or len(stored_digest) != 64\n            or any(character not in '0123456789abcdef' for character in stored_digest)):\n        raise ClaimError('approved hash must be lowercase SHA-256 hexadecimal')\n    if not secrets.compare_digest(digest, stored_digest):\n        raise ClaimError('approved text hash does not match')","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/operator-approval-loop/references/approval_claims.py#L29-L65","documentation":"When a sqlite3.Error (any SQLite-level failure such as a locked database, constraint violation, or I/O error) escapes the guarded transaction, the library rolls everything back and re-raises it as this generic ClaimError, chaining the original. The message emphasizes that no dispatch permission was granted, so the caller must not treat the operation as partially done.","triggerScenarios":"BEGIN IMMEDIATE hitting SQLITE_BUSY after the 5s timeout (another writer holds the DB); an INSERT/UPDATE inside claim() violating a UNIQUE or FOREIGN KEY constraint; disk I/O or database-corruption errors during the transaction.","commonSituations":"Concurrent workers contending for the same SQLite file; attempting claim() twice for the same obligation hitting a uniqueness constraint; read-only filesystem or missing database file in mode=rw.","solutions":["Inspect error.__cause__ (the original sqlite3.Error) to identify the underlying SQLite failure","For SQLITE_BUSY/locked errors, serialize writers or retry with backoff after checking no claim was created","Fix constraint violations (e.g. duplicate obligation_id in approval_bound_drafts) in your data before retrying","Ensure the database file is writable and the schema matches what the library expects"],"exampleFix":"// before\ntry:\n    token = claim(db, oid, did, now=ts)\nexcept sqlite3.OperationalError:  # never raised; wrapped\n    ...\n\n// after\ntry:\n    token = claim(db, oid, did, now=ts)\nexcept ClaimError as e:\n    cause = e.__cause__\n    if isinstance(cause, sqlite3.OperationalError) and 'locked' in str(cause):\n        retry_with_backoff()\n    else:\n        raise","handlingStrategy":"try-catch","validationCode":"# Pre-flight: ensure DB is reachable and writable\nrow = db.execute('SELECT 1').fetchone()  # raises sqlite3.Error early if broken","typeGuard":null,"tryCatchPattern":"try:\n    token = claim(db, oid, did, now=ts)\nexcept ClaimError as e:\n    cause = e.__cause__\n    if isinstance(cause, sqlite3.OperationalError) and 'locked' in str(cause):\n        schedule_retry_with_backoff()\n    elif isinstance(cause, sqlite3.IntegrityError):\n        log_duplicate_or_fk_issue(oid, did)\n    else:\n        raise\n# On any ClaimError here, treat NO permission as granted.","preventionTips":["Keep SQLite writer contention low; serialize claim writes across workers","Set a generous busy timeout and retry SQLITE_BUSY with exponential backoff","Fix constraint conflicts in data before retrying the same claim","Always read __cause__ to see the real SQLite error"],"tags":["sqlite","transactions","error-wrapping"],"backgroundTag":"database-write-failed","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}