iflytek/astron-agent · error · CustomException

20201

20201

Error message

Flow ID not found

What it means

The layout update endpoint looks up the Flow row by numeric id (session.query(Flow).filter_by(id=int(flow_id)).first()) and raises FLOW_NOT_FOUND_ERROR (20201) when no row matches. The DSL validated fine, but there is no persisted flow with that id to update.

Solutions

  1. Verify the flow_id exists: run SELECT id FROM flow WHERE id = <id> against the configured database.
  2. Refresh the flow list from the API and use a current id; if the flow was deleted, recreate it.
  3. Check DB connection config (host/database name) — the id may exist in a different environment.
  4. Confirm you are passing the flow's numeric id, not an app_id or other identifier.

Example fix

# before
await update_layout(flow_id="999999", dsl=dsl)  # stale id

# after
flows = await list_flows()
if any(str(f.id) == flow_id for f in flows):
    await update_layout(flow_id=flow_id, dsl=dsl)
else:
    flow_id = await create_flow(dsl=dsl)
Defensive patterns

Strategy: try-catch

Validate before calling

if session.query(Flow).filter_by(id=int(flow_id)).first() is None:
    raise ValueError(f"flow {flow_id} does not exist")

Type guard

def flow_exists(session, flow_id) -> bool:
    return session.query(Flow).filter_by(id=int(flow_id)).first() is not None

Try / catch

try:
    await update_layout(flow_id=flow_id, dsl=dsl)
except CustomException as e:
    if e.code == CodeEnum.FLOW_NOT_FOUND_ERROR.code:
        flow_id = await create_flow(dsl=dsl)  # recreate or refresh id
    else:
        raise

Prevention

When it happens

Trigger: PUT/update on the flow layout route with a flow_id that does not exist in the flows table; int(flow_id) succeeds (numeric string) but the row was deleted or belongs to another environment/database.

Common situations: Client keeps a flow_id from a deleted flow; environment mismatch (dev id used against prod DB); id vs string/other-key confusion (passing app_id as flow_id); database pointed at wrong schema via config.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/fb13ac29aa977a4f. Report an issue: GitHub.

Appendix: source

Thrown at core/workflow/api/v1/flow/layout.py:185

    span = Span()
    m = Meter()
    with span.start(
        attributes={"flow_id": flow_id},
    ) as current_span:
        try:
            await current_span.add_info_event_async(f"update start: {flow_id}")
            del_flow_by_id(flow_id)
            sparkflow_protocol = sanitize_protocol_document_for_use(flow.data)
            if sparkflow_protocol:
                if isinstance(sparkflow_protocol, str):
                    sparkflow_protocol = json.loads(sparkflow_protocol)
                WorkflowEngineFactory.create_engine(
                    WorkflowDSL.model_validate(sparkflow_protocol.get("data")),
                    current_span,
                )
            db_flow = session.query(Flow).filter_by(id=int(flow_id)).first()
            if not db_flow:
                raise CustomException(CodeEnum.FLOW_NOT_FOUND_ERROR)

            flow_service.update(session, db_flow, flow)
            m.in_success_count()
            return Resp.success(None, span.sid)
        except ValidationError as err:
            validation_err = _protocol_validation_exception(err)
            current_span.record_exception(validation_err)
            m.in_error_count(validation_err.code, span=current_span)
            return Resp.error(
                validation_err.code,
                validation_err.message,
                span.sid,
            )
        except CustomException as err:
            current_span.record_exception(err)
            m.in_error_count(err.code, span=current_span)
            return Resp.error(err.code, err.message, span.sid)
        except Exception as e:

View on GitHub (pinned to 5e758547a8)