Skip to content

Document that the whole leading comment block is parsed as the runner JSON #487

Description

@Thebeatkicks

Every Intelligent Contract starts with a runner comment:

# { "Depends": "py-genlayer:<hash>" }

What is not documented anywhere we could find is that GenVM parses the entire
contiguous run of leading # lines as that one JSON document. So this is a
valid contract:

# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }

# Anything you want to say about the contract.
from genlayer import *

and this one is rejected by the network, purely because the blank line is gone:

# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }
# Anything you want to say about the contract.
from genlayer import *

A single # hello on line 2 is enough. Reproducible without spending anything,
against Bradbury (2026-09-04) — the first form returns a schema, the second
returns VMError: invalid_contract:

$ curl -s -X POST -H 'Content-Type: application/json' \
    -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"gen_getContractSchema\",\"params\":[{\"code\":\"$(base64 -w0 < contract.py)\"}]}" \
    https://rpc-bradbury.genlayer.com
{"jsonrpc":"2.0","result":null,"error":{"code":-32000,"message":"VMError: invalid_contract"},"id":1}

The execution trace names the cause, and the message is the confusing part:

error: { causes: [ 'trailing characters at line 1 column 84' ] }

Line 1 is 83 characters long and entirely correct. Column 84 is the newline —
the parser is reporting where line 2 got appended to it. On the attest call
against the resulting address the trace instead says
VMError(invalid_contract absent_runner_comment), which points at a runner
comment that is present and well-formed.

What makes this expensive is that nothing local catches it:

  • genvm-lint check passes the broken file.
  • The direct-mode test suite passes the broken file.
  • genlayer deploy prints ✔ Contract deployed successfully. and returns a
    contract address.

The first real symptom is genlayer code <address> returning contract code not found at address …, or every call failing, against an address the CLI just
told you was deployed. We burned a deployment and an attest transaction
before finding it.

Suggested fixes, in order of how much they would have helped us:

  1. Document the rule on the Intelligent Contracts introduction, next to the
    runner comment: the runner comment must be the only leading comment, or must
    be separated from any other comment by a blank line.
  2. Have genvm-lint check it. It already parses the runner comment to
    resolve the version; rejecting a leading block that is not valid JSON would
    move this failure from a wasted deployment to a local lint error.
  3. Improve the error. absent_runner_comment for a file whose first line
    is a runner comment sends readers to exactly the wrong place; naming the
    comment block would be enough.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions