infiniflow/ragflow · error · Error

main() returned a non-JSON-serializable value.

Error message

main() returned a non-JSON-serializable value.

What it means

Raised when projects.get() in validate_connector_settings raises GitlabGetError — typically HTTP 404, meaning the project path f"{owner}/{name}" does not exist or is invisible to the token. Wrapped as ConnectorValidationError so the UI can ask the user to fix the config.

Source

Thrown at agent/sandbox/result_protocol.py:54


def build_javascript_wrapper(code: str, args_json: str) -> str:
    return f"""{code}

const __ragflowArgs = {args_json};

(async () => {{
  const __ragflowMain = typeof main !== 'undefined' ? main : module.exports && module.exports.main;
  if (typeof __ragflowMain !== 'function') {{
    throw new Error('main() must be defined or exported.');
  }}
  const output = await Promise.resolve(__ragflowMain(__ragflowArgs));
  if (typeof output === 'undefined') {{
    throw new Error('main() must return a value. Use null for an empty result.');
  }}
  const payload = JSON.stringify({{ present: true, value: output, type: 'json' }});
  if (typeof payload === 'undefined') {{
    throw new Error('main() returned a non-JSON-serializable value.');
  }}
  console.log('{RESULT_MARKER_PREFIX}' + Buffer.from(payload, 'utf8').toString('base64'));
}})();
"""


def extract_structured_result(stdout: str) -> tuple[str, dict[str, Any]]:
    if not stdout:
        return "", {}

    cleaned_lines: list[str] = []
    structured_result: dict[str, Any] = {}

    for line in str(stdout).splitlines():
        if line.startswith(RESULT_MARKER_PREFIX):
            payload_b64 = line[len(RESULT_MARKER_PREFIX) :].strip()
            if not payload_b64:
                cleaned_lines.append(line)

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Confirm the exact path from the project page: Settings > General > Advanced > Change path, or the canonical group/project slug
  2. For subgroups use the full nested owner, e.g. 'group/subgroup/project' → owner='group/subgroup', name='project'
  3. Ensure the token user is a member of the project if it is private
  4. If the project was transferred, update the connector config to the new namespace path

Example fix

# before: full URL / partial path
connector = GitlabConnector(project_owner="https://gitlab.com/acme", project_name="search")

# after: exact namespace path segments
connector = GitlabConnector(project_owner="acme/infra", project_name="search")
Defensive patterns

Strategy: validation

Validate before calling

import re

def parse_gitlab_project_path(url_or_path: str) -> tuple[str, str]:
    p = url_or_path.strip().strip("/")
    p = re.sub(r"^https?://[^/]+/", "", p)
    p = p.removesuffix(".git")
    parts = p.split("/")
    if len(parts) < 2:
        raise ValueError("Expected <owner>/<project>, got " + url_or_path)
    return "/".join(parts[:-1]), parts[-1]

Try / catch

from common.data_source.exceptions import ConnectorValidationError

try:
    connector.validate_connector_settings()
except ConnectorValidationError as e:
    if "not found" in str(e):
        # re-resolve path (project may have been renamed) and retry once
        connector.project_owner, connector.project_name = \
            resolve_current_path(connector.gitlab_client, connector.project_owner, connector.project_name)

Prevention

When it happens

Trigger: project_owner or project_name is misspelled, the project was renamed/transferred/deleted, a URL was pasted into the owner field, or the project is private and the token's user lacks any membership (GitLab returns 404, not 403, for hidden private projects).

Common situations: Copy-pasting the full HTTPS repo URL into the project owner field, renamed groups (old path 404s unless a redirect exists and redirects are disabled for API), subgroups where only the last segment was entered as owner.

Related errors


AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15). Data as JSON: /api/errors/91f6cee947ee56d9. Report an issue: GitHub.