Skip to content

feat: allow alembic startup when db is at newer schema#10878

Closed
jordanrfrazier wants to merge 5 commits into
mainfrom
allow-alembic-rollbacks
Closed

feat: allow alembic startup when db is at newer schema#10878
jordanrfrazier wants to merge 5 commits into
mainfrom
allow-alembic-rollbacks

Conversation

@jordanrfrazier
Copy link
Copy Markdown
Collaborator

@jordanrfrazier jordanrfrazier commented Dec 4, 2025

Allows langflow to start up and bypass alembic migration check when the database is at a newer schema than the source. This allows rollback of Langflow versioning for any reason without downgrading the database and potentially losing user data.

With the combination of migration guardrails assuring backwards-compatibility, this allows a previous langflow version to function normally on a newer database schema.

Note that the "is_db_ahead" assumes that a revision that cannot be found == ahead. There may be branching or corrupted states that are false positives.

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced database migration error detection to identify and gracefully handle schema version conflicts
    • Improved application startup when database schema is ahead of or misaligned with application code
    • Better error handling and logging during database initialization failures
  • Tests

    • Added comprehensive unit tests for migration compatibility and rollback scenarios

✏️ Tip: You can customize this high-level summary in your review settings.

jordanrfrazier and others added 2 commits December 3, 2025 20:03
Allow langflow to start up when database is at newer migration
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 4, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This change adds database migration state detection to identify when the database schema is ahead of or behind the code migrations. It enhances error handling in the migration flow by distinguishing between specific Alembic error conditions and deciding whether to allow startup or propagate errors. Includes comprehensive unit tests.

Changes

Cohort / File(s) Summary
Migration state detection logic
src/backend/base/langflow/services/database/service.py
Adds _check_if_database_ahead() and _handle_database_ahead() methods to analyze Alembic error messages, extract revisions, and determine schema state. Integrates these checks into _run_migrations() to conditionally allow startup or retry based on database-ahead detection. Expands Alembic imports to include script for revision lookups.
Error handling enhancement
src/backend/base/langflow/services/database/utils.py
Refactors initialize_database() CommandError handling into three explicit branches: "Can't locate revision" → log info and return; "overlaps with other requested revisions" → log warning, drop alembic_version table, retry, and return; other errors → re-raise. Centralizes error message extraction.
Alembic migration tests
src/backend/tests/unit/services/database/test_alembic_rollback.py
Adds comprehensive unit test module covering _check_if_database_ahead(), _handle_database_ahead(), and _run_migrations() under varied scenarios (DB ahead, DB behind, upgrade failures, overlapping revisions). Validates revision extraction from Alembic error messages and control flow decisions via mocks and patches.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant DS as DatabaseService
    participant Alembic
    participant DB as Database
    
    App->>DS: _run_migrations()
    DS->>Alembic: Check migration status
    
    alt Migration check fails
        Alembic-->>DS: CommandError
        DS->>DS: _check_if_database_ahead()
        alt Database is ahead
            DS->>DS: Log warning: DB ahead of code
            DS-->>App: Return (allow startup)
        else Database not ahead
            DS->>Alembic: Attempt upgrade
            alt Upgrade succeeds
                Alembic->>DB: Apply migrations
                DB-->>Alembic: OK
                Alembic-->>DS: Success
                DS-->>App: Return (startup)
            else Upgrade fails
                Alembic-->>DS: CommandError
                DS->>DS: _check_if_database_ahead() (retry)
                alt Database is ahead (confirmed)
                    DS->>DS: Log warning: DB ahead of code
                    DS-->>App: Return (allow startup)
                else Still not ahead
                    DS-->>App: Re-raise error
                end
            end
        end
    else Migration check succeeds
        Alembic-->>DS: OK
        DS-->>App: Continue startup
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Areas requiring extra attention:

  • Alembic error message parsing logic in _check_if_database_ahead() and _handle_database_ahead() — verify regex/string matching handles edge cases
  • Integration points in _run_migrations() where new ahead-checks are inserted — ensure control flow doesn't inadvertently suppress legitimate errors
  • Test coverage for revision extraction with special characters and quote variants — validate parsing robustness

Possibly related PRs

Suggested labels

enhancement, size:L

Suggested reviewers

  • rjordanfrazier

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Test File Naming And Structure ⚠️ Warning Test file mentioned in PR summary (src/backend/tests/unit/services/database/test_alembic_rollback.py) does not exist in repository; directory structure is incomplete. Create the missing test file with proper pytest structure, descriptive test function names, fixtures, parametrized tests for edge cases, and comprehensive coverage of new methods _check_if_database_ahead and _handle_database_ahead including mocking and error validation.
Excessive Mock Usage Warning ❓ Inconclusive Test file test_alembic_rollback.py does not exist in the repository. Cannot assess mock usage patterns without reviewing actual test code. Locate and provide the test file to evaluate mock usage, mock types, and whether real test doubles could replace mocks to improve test design.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: allowing Alembic to start when the database schema is newer than the code, which is the core objective of this PR.
Docstring Coverage ✅ Passed Docstring coverage is 86.96% which is sufficient. The required threshold is 80.00%.
Test Coverage For New Implementations ✅ Passed PR includes comprehensive test file with 15 well-structured test functions thoroughly covering new database migration functionality across multiple scenarios and edge cases.
Test Quality And Coverage ✅ Passed The test suite demonstrates solid quality with 18 distinct test scenarios, 87 mock usages, and 43 assertions covering unit, integration, and async scenarios. All new methods are tested with positive and negative cases including edge scenarios. Error handling is validated appropriately using mocks.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the enhancement New feature or request label Dec 4, 2025
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Dec 4, 2025
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Dec 4, 2025
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Dec 4, 2025

Frontend Unit Test Coverage Report

Coverage Summary

Lines Statements Branches Functions
Coverage: 15%
15.43% (4244/27499) 8.61% (1811/21013) 9.69% (587/6057)

Unit Test Results

Tests Skipped Failures Errors Time
1671 0 💤 0 ❌ 0 🔥 21.349s ⏱️

@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 4, 2025

Codecov Report

❌ Patch coverage is 95.65217% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 32.61%. Comparing base (f5a50c1) to head (d63d4aa).
⚠️ Report is 436 commits behind head on main.

Files with missing lines Patch % Lines
...backend/base/langflow/services/database/service.py 94.28% 2 Missing ⚠️

❌ Your project status has failed because the head coverage (39.96%) is below the target coverage (60.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main   #10878      +/-   ##
==========================================
+ Coverage   32.55%   32.61%   +0.05%     
==========================================
  Files        1370     1370              
  Lines       63544    63581      +37     
  Branches     9394     9394              
==========================================
+ Hits        20685    20735      +50     
+ Misses      41820    41807      -13     
  Partials     1039     1039              
Flag Coverage Δ
backend 51.77% <95.65%> (+0.18%) ⬆️
frontend 14.28% <ø> (ø)
lfx 39.96% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...c/backend/base/langflow/services/database/utils.py 72.30% <100.00%> (+13.97%) ⬆️
...backend/base/langflow/services/database/service.py 67.97% <94.28%> (+7.48%) ⬆️

... and 5 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Dec 4, 2025
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/backend/tests/unit/services/database/test_alembic_rollback.py (2)

299-341: Verify mock session context manager setup.

The mock session setup for the async context manager pattern (lines 318-321) looks correct, but the test should verify that session.exec was called with the DROP TABLE statement.

Consider adding an assertion to verify the DROP TABLE was executed:

             # Verify run_migrations was called twice
             assert mock_db_service.run_migrations.call_count == 2
+            
+            # Verify DROP TABLE was executed
+            mock_session.exec.assert_called_once()
+            call_args = mock_session.exec.call_args[0][0]
+            assert "DROP TABLE alembic_version" in str(call_args)

398-398: Remove trailing debug comment.

This appears to be a signature or debug comment that should be removed before merging.

-# Made with Bob
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5a50c1 and 2b35f71.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • src/backend/base/langflow/services/database/service.py (3 hunks)
  • src/backend/base/langflow/services/database/utils.py (1 hunks)
  • src/backend/tests/unit/services/database/test_alembic_rollback.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/backend/**/*.py

📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)

src/backend/**/*.py: Use FastAPI async patterns with await for async operations in component execution methods
Use asyncio.create_task() for background tasks and implement proper cleanup with try/except for asyncio.CancelledError
Use queue.put_nowait() for non-blocking queue operations and asyncio.wait_for() with timeouts for controlled get operations

Files:

  • src/backend/tests/unit/services/database/test_alembic_rollback.py
  • src/backend/base/langflow/services/database/service.py
  • src/backend/base/langflow/services/database/utils.py
src/backend/tests/**/*.py

📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)

src/backend/tests/**/*.py: Place backend unit tests in src/backend/tests/ directory, component tests in src/backend/tests/unit/components/ organized by component subdirectory, and integration tests accessible via make integration_tests
Use same filename as component with appropriate test prefix/suffix (e.g., my_component.pytest_my_component.py)
Use the client fixture (FastAPI Test Client) defined in src/backend/tests/conftest.py for API tests; it provides an async httpx.AsyncClient with automatic in-memory SQLite database and mocked environment variables. Skip client creation by marking test with @pytest.mark.noclient
Inherit from the correct ComponentTestBase family class located in src/backend/tests/base.py based on API access needs: ComponentTestBase (no API), ComponentTestBaseWithClient (needs API), or ComponentTestBaseWithoutClient (pure logic). Provide three required fixtures: component_class, default_kwargs, and file_names_mapping
Create comprehensive unit tests for all new backend components. If unit tests are incomplete, create a corresponding Markdown file documenting manual testing steps and expected outcomes
Test both sync and async code paths, mock external dependencies appropriately, test error handling and edge cases, validate input/output behavior, and test component initialization and configuration
Use @pytest.mark.asyncio decorator for async component tests and ensure async methods are properly awaited
Test background tasks using asyncio.create_task() and verify completion with asyncio.wait_for() with appropriate timeout constraints
Test queue operations using non-blocking queue.put_nowait() and asyncio.wait_for(queue.get(), timeout=...) to verify queue processing without blocking
Use @pytest.mark.no_blockbuster marker to skip the blockbuster plugin in specific tests
For database tests that may fail in batch runs, run them sequentially using uv run pytest src/backend/tests/unit/test_database.py r...

Files:

  • src/backend/tests/unit/services/database/test_alembic_rollback.py
**/test_*.py

📄 CodeRabbit inference engine (Custom checks)

**/test_*.py: Review test files for excessive use of mocks that may indicate poor test design - check if tests have too many mock objects that obscure what's actually being tested
Warn when mocks are used instead of testing real behavior and interactions, and suggest using real objects or test doubles when mocks become excessive
Ensure mocks are used appropriately for external dependencies only, not for core logic
Backend test files should follow the naming convention test_*.py with proper pytest structure
Test files should have descriptive test function names that explain what is being tested
Tests should be organized logically with proper setup and teardown
Consider including edge cases and error conditions for comprehensive test coverage
Verify tests cover both positive and negative scenarios where appropriate
For async functions in backend tests, ensure proper async testing patterns are used with pytest
For API endpoints, verify both success and error response testing

Files:

  • src/backend/tests/unit/services/database/test_alembic_rollback.py
🧠 Learnings (8)
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : Create comprehensive unit tests for all new backend components. If unit tests are incomplete, create a corresponding Markdown file documenting manual testing steps and expected outcomes

Applied to files:

  • src/backend/tests/unit/services/database/test_alembic_rollback.py
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : Test both sync and async code paths, mock external dependencies appropriately, test error handling and edge cases, validate input/output behavior, and test component initialization and configuration

Applied to files:

  • src/backend/tests/unit/services/database/test_alembic_rollback.py
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : Use `monkeypatch` fixture to mock internal functions for testing error handling scenarios; validate error status codes and error message content in responses

Applied to files:

  • src/backend/tests/unit/services/database/test_alembic_rollback.py
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : Test component versioning and backward compatibility using `file_names_mapping` fixture with `VersionComponentMapping` objects mapping component files across Langflow versions

Applied to files:

  • src/backend/tests/unit/services/database/test_alembic_rollback.py
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : Place backend unit tests in `src/backend/tests/` directory, component tests in `src/backend/tests/unit/components/` organized by component subdirectory, and integration tests accessible via `make integration_tests`

Applied to files:

  • src/backend/tests/unit/services/database/test_alembic_rollback.py
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : For database tests that may fail in batch runs, run them sequentially using `uv run pytest src/backend/tests/unit/test_database.py` rather than in batch mode

Applied to files:

  • src/backend/tests/unit/services/database/test_alembic_rollback.py
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : Each test should have a clear docstring explaining its purpose; complex test setups should be commented; mock usage should be documented; expected behaviors should be explicitly stated

Applied to files:

  • src/backend/tests/unit/services/database/test_alembic_rollback.py
📚 Learning: 2025-11-24T19:46:09.104Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/backend_development.mdc:0-0
Timestamp: 2025-11-24T19:46:09.104Z
Learning: Applies to src/backend/base/langflow/services/database/models/**/*.py : Database models should be organized by domain (api_key/, flow/, folder/, user/, etc.) under `src/backend/base/langflow/services/database/models/`

Applied to files:

  • src/backend/base/langflow/services/database/service.py
🧬 Code graph analysis (1)
src/backend/base/langflow/services/database/utils.py (1)
src/backend/base/langflow/services/database/service.py (1)
  • run_migrations (467-477)
🪛 GitHub Actions: Ruff Style Check
src/backend/base/langflow/services/database/service.py

[error] 350-350: Ruff: Trailing whitespace (W291).

🪛 GitHub Check: Ruff Style Check (3.13)
src/backend/base/langflow/services/database/service.py

[failure] 388-388: Ruff (W293)
src/backend/base/langflow/services/database/service.py:388:1: W293 Blank line contains whitespace


[failure] 385-385: Ruff (BLE001)
src/backend/base/langflow/services/database/service.py:385:16: BLE001 Do not catch blind exception: Exception


[failure] 377-377: Ruff (BLE001)
src/backend/base/langflow/services/database/service.py:377:20: BLE001 Do not catch blind exception: Exception


[failure] 376-376: Ruff (TRY300)
src/backend/base/langflow/services/database/service.py:376:17: TRY300 Consider moving this statement to an else block


[failure] 370-370: Ruff (W293)
src/backend/base/langflow/services/database/service.py:370:1: W293 Blank line contains whitespace


[failure] 368-368: Ruff (W293)
src/backend/base/langflow/services/database/service.py:368:1: W293 Blank line contains whitespace


[failure] 361-361: Ruff (W293)
src/backend/base/langflow/services/database/service.py:361:1: W293 Blank line contains whitespace


[failure] 355-355: Ruff (W293)
src/backend/base/langflow/services/database/service.py:355:1: W293 Blank line contains whitespace


[failure] 351-351: Ruff (W293)
src/backend/base/langflow/services/database/service.py:351:1: W293 Blank line contains whitespace


[failure] 350-350: Ruff (W291)
src/backend/base/langflow/services/database/service.py:350:19: W291 Trailing whitespace

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (16)
  • GitHub Check: Test Docker Images / Test docker images
  • GitHub Check: Lint Backend / Run Mypy (3.11)
  • GitHub Check: Lint Backend / Run Mypy (3.12)
  • GitHub Check: Run Frontend Tests / Determine Test Suites and Shard Distribution
  • GitHub Check: Lint Backend / Run Mypy (3.10)
  • GitHub Check: Lint Backend / Run Mypy (3.13)
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 2
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 4
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 1
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 3
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 5
  • GitHub Check: Run Backend Tests / LFX Tests - Python 3.10
  • GitHub Check: Test Starter Templates
  • GitHub Check: Run Backend Tests / Integration Tests - Python 3.10
  • GitHub Check: Update Component Index
  • GitHub Check: Optimize new Python code in this PR
🔇 Additional comments (9)
src/backend/tests/unit/services/database/test_alembic_rollback.py (5)

17-31: Good test structure with clear docstrings.

The test correctly binds the real method to a mock instance using __get__, allowing isolated testing of _check_if_database_ahead without instantiating the full DatabaseService.


53-81: Thorough test for database-ahead detection.

The test properly validates:

  • Return value is True when revision not found in code
  • Warning log includes both DB revision and code head
  • Correct revision extracted from error message

139-176: LGTM - Good coverage of handler method.

Both return paths are tested with appropriate assertions on logging behavior.


204-225: Good test for upgrade failure fallback.

This test validates the important fallback path where database-ahead detection happens during upgrade failure, not just during the initial check. The side_effect=[False, True] pattern correctly simulates the two-call scenario.


368-396: LGTM - Good regex edge case coverage.

Testing the regex pattern directly ensures it handles various quote styles and special characters correctly.

src/backend/base/langflow/services/database/service.py (3)

389-401: LGTM - Clean handler implementation.

The method properly encapsulates the check-and-log pattern, providing a clear info message when database is ahead.


432-453: Good fallback handling on upgrade failure.

The control flow correctly:

  1. Checks if DB is ahead after initial check failure
  2. Attempts upgrade if not ahead
  3. Re-checks if ahead on upgrade failure before re-raising

The time.sleep(3) on line 448 is consistent with the existing pattern on line 492.


15-15: LGTM - Import addition is appropriate.

The script module is needed for ScriptDirectory.from_config() in the new _check_if_database_ahead method, and util is already used elsewhere in the file for exception types.

src/backend/base/langflow/services/database/utils.py (1)

41-62: Async patterns are correctly implemented for the error handling logic.

The code properly follows FastAPI async patterns:

  • session_getter is correctly decorated with @asynccontextmanager and implements proper session lifecycle management with try/except/finally and appropriate await calls
  • await database_service.run_migrations() is correctly awaited
  • await session.exec() for the DROP TABLE operation follows the non-blocking pattern requirement

The three-way branching for CommandError cases is well-structured:

  1. Database ahead → log and allow startup
  2. Overlapping revisions → drop table and retry
  3. Unknown errors → re-raise

One consideration: the DROP TABLE alembic_version on line 57 is a destructive operation. Ensure this is the intended recovery mechanism for overlapping revisions, as it forces a full re-migration stamp.

Comment on lines +345 to +388
def _check_if_database_ahead(self, alembic_cfg, error_msg: str) -> bool:
"""Check if database is ahead of code based on error message.

If error contains "Can't locate revision", we check if the DB revision
exists in the code. If not, the database is ahead (we assume. This isn't
foolproof)

Args:
alembic_cfg: Alembic configuration
error_msg: Error message from command.check()

Returns:
True if database appears to be ahead, False otherwise
"""
if "Can't locate revision identified by" not in error_msg:
return False

try:
# Extract revision from error message
# Format: "Can't locate revision identified by 'abc123'"
match = re.search(r"identified by ['\"]([^'\"]+)['\"]", error_msg)
if not match:
return False

db_revision = match.group(1)

# Check if this revision exists in the code
script_dir = script.ScriptDirectory.from_config(alembic_cfg)
try:
script_dir.get_revision(db_revision)
# Revision exists in code, so DB is not ahead
return False
except Exception:
# Revision doesn't exist in code - database is ahead
code_head = script_dir.get_current_head()
logger.warning(
f"Database revision '{db_revision}' is ahead of code's head revision '{code_head}'. "
"Allowing startup assuming backwards-compatible migrations."
)
return True
except Exception as exc:
logger.debug(f"Could not determine if database is ahead: {exc}")
return False

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's check the actual file to see current state
head -n 400 "src/backend/base/langflow/services/database/service.py" | tail -n 70

Repository: langflow-ai/langflow

Length of output: 2813


🌐 Web query:

alembic ScriptDirectory.get_revision exception ResolutionError

💡 Result:

The ResolutionError from ScriptDirectory.get_revision means Alembic could not resolve the revision id/label you asked for (e.g. "No such revision or branch 'abcd...'"). Common causes and fixes:

  1. Wrong revision id (partial id ambiguous or incorrect) — use the full revision id or run alembic history to list revisions. [1][2]
  2. script_location mismatch (Alembic is reading a different migrations directory) — confirm Config().get_main_option("script_location") or use ScriptDirectory.from_config with the correct config. [1]
  3. Missing/corrupt migration file(s) (file deleted, renamed, or not committed) — check your versions/ folder for the expected revision file. Restoring the file or re-creating the migration fixes it. [2]
  4. Branching / multiple heads / merge points — symbolic names like "head" may refer to multiple revisions; use get_heads() or specify the correct branch. [1]
  5. DB alembic_version mismatch — the DB might reference a revision that no longer exists; either restore the migration file or align DB with alembic (e.g. alembic stamp after verifying). [2][3]

Quick troubleshooting commands:

  • alembic history --verbose (list revisions). [1]
  • alembic heads / alembic current (inspect heads / DB current). [1]
  • Inspect your migrations directory for the revision file (versions/_*.py). [2]
  • If DB is ahead/behind and you know the correct state, use alembic stamp or recreate the missing revision file. [2][3]

Sources: Alembic ScriptDirectory / Revision docs and community reports showing ResolutionError causes and fixes. [1][2][3]

References:
[1] Alembic ScriptDirectory / Revision docs.
[2] StackOverflow example of ResolutionError when a revision id is missing.
[3] GitHub issue showing ResolutionError caused by missing/renamed revisions and using stamp/restore as remedies.


🏁 Script executed:

# Check if alembic is available and examine its source
python3 << 'EOF'
import inspect
try:
    import alembic.script.revision as alembic_rev
    import alembic.script
    
    # Check what exceptions are available
    print("Available exceptions in alembic.script.revision:")
    for name in dir(alembic_rev):
        obj = getattr(alembic_rev, name)
        if isinstance(obj, type) and issubclass(obj, Exception):
            print(f"  - {name}")
    
    print("\nAvailable exceptions in alembic.script:")
    import alembic.script as script_mod
    for name in dir(script_mod):
        obj = getattr(script_mod, name)
        if isinstance(obj, type) and issubclass(obj, Exception):
            print(f"  - {name}")
    
    # Try to find get_revision method signature
    print("\nScriptDirectory.get_revision signature:")
    from alembic.script import ScriptDirectory
    sig = inspect.signature(ScriptDirectory.get_revision)
    print(f"  {sig}")
    
    # Get docstring if available
    if ScriptDirectory.get_revision.__doc__:
        print(f"  Docstring: {ScriptDirectory.get_revision.__doc__[:200]}")
        
except ImportError as e:
    print(f"Alembic not available: {e}")
EOF

Repository: langflow-ai/langflow

Length of output: 150


🏁 Script executed:

# Check imports in the file to see what's already imported from alembic
head -n 50 "src/backend/base/langflow/services/database/service.py" | grep -E "^from|^import"

Repository: langflow-ai/langflow

Length of output: 1418


🏁 Script executed:

# Check if alembic.script.revision.ResolutionError is already available or needs import
grep -n "from alembic\|import alembic" "src/backend/base/langflow/services/database/service.py" | head -20

Repository: langflow-ai/langflow

Length of output: 145


🏁 Script executed:

# Verify the exact exception class path
python3 << 'EOF'
try:
    from alembic.script.revision import ResolutionError
    print("✓ ResolutionError can be imported from alembic.script.revision")
    print(f"  Exception class: {ResolutionError}")
    print(f"  Module: {ResolutionError.__module__}")
    print(f"  Base classes: {ResolutionError.__bases__}")
except ImportError as e:
    print(f"✗ Cannot import ResolutionError: {e}")
    
# Also check if it's available via alembic.script
try:
    from alembic.script import ResolutionError as ResolutionError2
    print("✓ ResolutionError also available from alembic.script")
except ImportError:
    print("✗ ResolutionError not available from alembic.script")
EOF

Repository: langflow-ai/langflow

Length of output: 174


Fix linting issues and improve exception handling.

Multiple style violations detected by Ruff:

  • Line 350: Trailing whitespace (W291) — pipeline failure
  • Lines 351, 355, 361, 368, 370, 388: Blank lines contain whitespace (W293)
  • Lines 377, 385: Blind exception catches (BLE001)
  • Line 376: Consider moving return False to an else block (TRY300)

The inner exception at line 377 should catch alembic.script.revision.ResolutionError instead of a blind Exception. This requires adding the import at the top of the file:

from alembic.script.revision import ResolutionError

Then update the exception handler to:

except ResolutionError:
    # Revision doesn't exist in code - database is ahead
    code_head = script_dir.get_current_head()
    logger.warning(
        f"Database revision '{db_revision}' is ahead of code's head revision '{code_head}'. "
        "Allowing startup assuming backwards-compatible migrations."
    )
    return True
else:
    # Revision exists in code, so DB is not ahead
    return False

The outer exception catch at line 385 can remain a blind catch with # noqa: BLE001 for robustness across multiple failure points. Also fix all whitespace violations per the Ruff report.

🧰 Tools
🪛 GitHub Actions: Ruff Style Check

[error] 350-350: Ruff: Trailing whitespace (W291).

🪛 GitHub Check: Ruff Style Check (3.13)

[failure] 388-388: Ruff (W293)
src/backend/base/langflow/services/database/service.py:388:1: W293 Blank line contains whitespace


[failure] 385-385: Ruff (BLE001)
src/backend/base/langflow/services/database/service.py:385:16: BLE001 Do not catch blind exception: Exception


[failure] 377-377: Ruff (BLE001)
src/backend/base/langflow/services/database/service.py:377:20: BLE001 Do not catch blind exception: Exception


[failure] 376-376: Ruff (TRY300)
src/backend/base/langflow/services/database/service.py:376:17: TRY300 Consider moving this statement to an else block


[failure] 370-370: Ruff (W293)
src/backend/base/langflow/services/database/service.py:370:1: W293 Blank line contains whitespace


[failure] 368-368: Ruff (W293)
src/backend/base/langflow/services/database/service.py:368:1: W293 Blank line contains whitespace


[failure] 361-361: Ruff (W293)
src/backend/base/langflow/services/database/service.py:361:1: W293 Blank line contains whitespace


[failure] 355-355: Ruff (W293)
src/backend/base/langflow/services/database/service.py:355:1: W293 Blank line contains whitespace


[failure] 351-351: Ruff (W293)
src/backend/base/langflow/services/database/service.py:351:1: W293 Blank line contains whitespace


[failure] 350-350: Ruff (W291)
src/backend/base/langflow/services/database/service.py:350:19: W291 Trailing whitespace

🤖 Prompt for AI Agents
In src/backend/base/langflow/services/database/service.py around lines 345 to
388, fix linting whitespace issues and tighten exception handling: remove
trailing/blank-line whitespace per Ruff, add the import "from
alembic.script.revision import ResolutionError" at the top of the file, replace
the inner blind except Exception that handles missing revision with "except
ResolutionError:" to mark the DB-as-ahead branch (log the warning and return
True there) and change the successful path to return False in an else block
after the try, and keep the outer broad exception catch but mark it with "#
noqa: BLE001" as suggested.

Copy link
Copy Markdown
Collaborator

@Adam-Aghili Adam-Aghili left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! just 1 non bloking questions

Also ruff failures

time.sleep(3)
except Exception as upgrade_exc:
# If upgrade fails, check if DB is ahead (might have been a transient error)
if self._handle_database_ahead(alembic_cfg, str(upgrade_exc)):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this here if we _handle_database_ahead above?

logger.debug(f"Error checking migrations: {exc}")

# Check if database is ahead of code (backwards-compatible scenario)
if self._handle_database_ahead(alembic_cfg, error_msg):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't this make the line 451 unnecessary?

@github-actions github-actions Bot added the lgtm This PR has been approved by a maintainer label Dec 4, 2025
@jordanrfrazier jordanrfrazier marked this pull request as draft February 13, 2026 15:22
@jordanrfrazier jordanrfrazier added the DO NOT MERGE Don't Merge this PR label Mar 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DO NOT MERGE Don't Merge this PR enhancement New feature or request lgtm This PR has been approved by a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants